곡선 알고리즘 사용 사례 특징
secp256r1 ECDSA 범용 (NIST 추천) 속도 느림
secp256k1 ECDSA 블록체인 속도 느림
Ed25519 EdDSA SSH 속도 빠름 / 공개키 : 256바이트 (고정 크기)

# secp256k1 예시

from ecdsa import SECP256k1, SigningKey, VerifyingKey
from ecdsa.util import sigencode_der, sigdecode_der
import hashlib

# Alice (서명자)
def alice_sign(message):
    # Alice의 개인키 생성
    sk = SigningKey.generate(curve=SECP256k1)
    # Alice의 공개키 생성
    vk = sk.get_verifying_key()
    
    # 메시지 해싱
    message_hash = hashlib.sha256(message.encode('utf-8')).digest()
    print(f"Alice가 해싱한 메시지: {message_hash.hex()}")
    
    # 서명 생성
    signature = sk.sign(message_hash, sigencode=sigencode_der)
    print(f"Alice의 서명: {signature.hex()}")
    
    return signature, vk

# Bob (검증자)
def bob_verify(message, signature, vk):
    # 메시지 해싱
    message_hash = hashlib.sha256(message.encode('utf-8')).digest()
    print(f"Bob이 해싱한 메시지: {message_hash.hex()}")
    
    # 서명 검증
    try:
        vk.verify(signature, message_hash, sigdecode=sigdecode_der)
        print("서명 검증 성공!")
        return True
    except:
        print("서명 검증 실패!")
        return False

# Alice가 서명
message = "Alice의 중요한 메시지"
print(f"서명할 메시지: {message}")
signature, alice_vk = alice_sign(message)

# Bob이 서명 검증
bob_verify(message, signature, alice_vk)
서명할 메시지: Alice의 중요한 메시지
Alice가 해싱한 메시지: 2491722cc10f5bd7bc9f79ae476ba2c1055dab43be2fca9dc81e0718a1381642
Alice의 서명: 3044022029160eb2534be33a8311639465202dcdee5a7725fc41cd9f01e1c8d986a66688022003c159499de24335b0c89d4a34cc35b0714b58d935ed615cc131b1ab2278d7ad
Bob이 해싱한 메시지: 2491722cc10f5bd7bc9f79ae476ba2c1055dab43be2fca9dc81e0718a1381642
서명 검증 성공!

서명 구조 (der)

SEQUENCE 태그, 서명 구조의 시작 30
서명 길이 44
 r의 INTEGER 태그 02
r의 길이 20 (0x20)
r 값  29 16 0E B2 53 4B E3 3A 83 11 63 94 65 20 2D CD EE 5A 77 25 FC 41 CD 9F 01 E1 C8 D9 86 A6 66 88
s의 INTEGER 태그 02
s의 길이 20 (0x20)
s 값 03 C1 59 49 9D E2 43 35 B0 C8 9D 4A 34 CC 35 B0 71 4B 58 D9 35 ED 61 5C C1 31 B1 AB 22 78 D7 AD

# secp256r1 예시

from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives import serialization
import hashlib

# Alice (서명자)
def alice_sign(message):
    # Alice의 개인키 생성 (secp256r1 사용)
    sk = ec.generate_private_key(ec.SECP256R1())
    
    # Alice의 공개키 생성
    vk = sk.public_key()
    
    # 메시지 해싱
    message_hash = hashlib.sha256(message.encode('utf-8')).digest()
    print(f"Alice가 해싱한 메시지: {message_hash.hex()}")
    
    # 서명 생성
    signature = sk.sign(message_hash, ec.ECDSA(hashes.SHA256()))
    print(f"Alice의 서명: {signature.hex()}")
    
    return signature, vk

# Bob (검증자)
def bob_verify(message, signature, vk):
    # 메시지 해싱
    message_hash = hashlib.sha256(message.encode('utf-8')).digest()
    print(f"Bob이 해싱한 메시지: {message_hash.hex()}")
    
    # 서명 검증
    try:
        vk.verify(signature, message_hash, ec.ECDSA(hashes.SHA256()))
        print("서명 검증 성공!")
        return True
    except:
        print("서명 검증 실패!")
        return False

# Alice가 서명
message = "Alice의 중요한 메시지"
print(f"서명할 메시지: {message}")
signature, alice_vk = alice_sign(message)

# Bob이 서명 검증
bob_verify(message, signature, alice_vk)
서명할 메시지: Alice의 중요한 메시지
Alice가 해싱한 메시지: 2491722cc10f5bd7bc9f79ae476ba2c1055dab43be2fca9dc81e0718a1381642
Alice의 서명: 304402202797f1bd7f59f0f2a7865655fd2999ca1d1e5158b29d546cb71aa57155ab901502201165c74887c2ad384c9f8cf6a7b4de771c4bd06467bf396422bcee39527b60d4
Bob이 해싱한 메시지: 2491722cc10f5bd7bc9f79ae476ba2c1055dab43be2fca9dc81e0718a1381642
서명 검증 성공!

서명 구조가 secp256k1과 동일

# ed25519 예시

from cryptography.hazmat.primitives.asymmetric import ed25519
from cryptography.hazmat.primitives import hashes
import hashlib

# Alice (서명자)
def alice_sign(message):
    # Alice의 개인키 생성 (ed25519 사용)
    sk = ed25519.Ed25519PrivateKey.generate()
    
    # Alice의 공개키 생성
    vk = sk.public_key()
    
    # 메시지 해싱
    message_hash = hashlib.sha256(message.encode('utf-8')).digest()
    print(f"Alice가 해싱한 메시지: {message_hash.hex()}")
    
    # 서명 생성
    signature = sk.sign(message_hash)
    print(f"Alice의 서명: {signature.hex()}")
    
    return signature, vk

# Bob (검증자)
def bob_verify(message, signature, vk):
    # 메시지 해싱
    message_hash = hashlib.sha256(message.encode('utf-8')).digest()
    print(f"Bob이 해싱한 메시지: {message_hash.hex()}")
    
    # 서명 검증
    try:
        vk.verify(signature, message_hash)
        print("서명 검증 성공!")
        return True
    except:
        print("서명 검증 실패!")
        return False

# Alice가 서명
message = "Alice의 중요한 메시지"
print(f"서명할 메시지: {message}")
signature, alice_vk = alice_sign(message)

# Bob이 서명 검증
bob_verify(message, signature, alice_vk)
서명할 메시지: Alice의 중요한 메시지
Alice가 해싱한 메시지: 2491722cc10f5bd7bc9f79ae476ba2c1055dab43be2fca9dc81e0718a1381642
Alice의 서명: 1a9e8142f0ca566e3bdb67330816c7592c2882d3c3ccd154d5c29c7795aabdc82271aa22370d64adcc1eedb868f9448d25fdbf407b145dda90ba08d8cf29fa00
Bob이 해싱한 메시지: 2491722cc10f5bd7bc9f79ae476ba2c1055dab43be2fca9dc81e0718a1381642
서명 검증 성공!

서명 구조

r (32바이트) 1a9e8142f0ca566e3bdb67330816c7592c2882d3c3ccd154d5c29c7795aabdc8
s (32바이트) 2271aa22370d64adcc1eedb868f9448d25fdbf407b145dda90ba08d8cf29fa00

https://github.com/codetronik/optee-aes

1. 키 설정

TA에서는 OP-TEE API를 활용하여 eMMC의 RPMB(Replay Protected Memory Block) 파티션에 키를 생성하고 삭제할 수 있다. 이 영역은 Normal World에서 접근할 수 없다.

별칭(alias)을 지정하여 키에 접근한다. (TA간 키는 공유할 수 없다. 즉, alias가 동일하더라도, 다른 TA의 alias에 접근할 수 없다.) RPMB에 키가 존재하지 않으면, 키를 생성하여 저장한다. 

TA 관련 주요 API들은 중요 데이터 저장을 위해 세션을 제공한다. 뭘 저장할 지는 자유이며, 필자는 이 곳에 키를 저장하였다.

2. AES-GCM을 구현

세션에서 키를 불러온 후, 이를 사용하여 데이터를 암/복호화한다. TA에서는 암호화 과정에서 IV를 랜덤하게 생성하며, 최종적으로 생성된 태그(tag)와 암호문(cipher)을 함께 반환한다.

소스 : https://github.com/codetronik/optee_example

프로젝트 구조는 아래와 같이 구성되어야 한다. (어떻게 만들던 상관없지만, Normal 과 TA는 분리되어 있어야 개발이 편해진다.)

├── include
│   └── common.h
├── normal
│   └── main.cpp
└── ta
    ├── Makefile
    ├── ta.c 
    ├── sub.mk // 필수 파일
    └── user_ta_header_defines.h // 필수 파일

유저가 OP-TEE OS의 Normal World(일반 리눅스 영역)에서 main을 실행하면, Secure World의 TA와 통신하게 된다.

TA 소스는 콜백 함수 구현이므로, 반드시 C로 작성하여야 컴파일이 된다. Normal은 C++로 작성해도 상관 없다. 

TA와 Normal 각각 컴파일 하여야 한다.

필자는 라즈베리파이를 사용 중이라 크로스컴파일러 설치를 안했으므로, 참고 바람.

normal의 경우 필자는 clang을 사용했다.

// normal
clang --sysroot=/home/code/optee/out-br/host/aarch64-buildroot-linux-gnu/sysroot -o main main.cpp -lteec -std=c++20 -lstdc++ -Wunused-parameter
// TA
make

TA 실행 파일(11223344-5566-7788-99aa-bbccddeeff00.ta)은 /lib/optee_armtz에 복사한다. Normal은 /tmp 등 적절한 곳에 복사한다. 우분투<->QEMU간 파일 전송은 #1편을 참조

Secure World 콘솔을 보면, Hello 가 로깅된 것을 확인할 수 있다.

참조 : https://optee.readthedocs.io/en/latest/building/trusted_applications.html

+ Recent posts