JOSE Header
- enc - content encryption알고리즘 정의, 대칭 AEAD(Authenticated Encryption with Associated Data) 알고리즘이어야 함.
- alg - CEK(Content Encryption Key)를 암호화하는 알고리즘 정의, 키 랩핑 알고리즘
JWE Encrypted Key
- 토큰 발행 시에 enc에 맞는 랜덤한 key를 생성하고 이를 alg의 알고리즘을 써서 암호화 진행
- 암호화된 키가 들어감.
JWE Initialization Vector(IV)
- 일부 초기화 벡터가 필요한 알고리즘을 위한 공란
- 항상 같은 결과가 나오는 것을 방지하기 위해 추가됨.
- AES-GCM알고리즘에서 사용
JWE Ciphertext
- CEK와 enc알고리즘으로(IV, AAD 사용) payload를 암호화한 값
JWE Authentication Tag
- ciphertext와 함께 생성됨
- 무결정 증명시 사용
JWE AAD
- 암호화된 payload와 함께 무결성을 증명하는데 사용
서명 과정(JWE Compact Serialization)
- CEK를 만들 알고리즘 파악
- CEK생성 및 Encrypted Key 계산, 이때 alg 및 JWK 사용
- Encrypted Key를 base64-url로 인코딩
- 임의의 Initialization Vector값 생성 및 base64-url 인코딩
- header를 UTF-8인코딩&base64url 인코딩 하여 Jose Header 생성
- Jose Header의 ASCII 값을 계산하여 AAD 생성
- CEK, IV, AAD를 이용해 payload 암호화
- AEAD를 사용해 Ciphertext와 Authentication Tag 생성
- Cipertext를 base64-url 인코딩하여 JWE Cipertext 생성
- Authentication Tag 를 base64-url 인코딩 하여 JWE Authenticate Tag생성
AES-GCM
AES(Advanced Encryption Standard)
- 암호화와 복호화 과정에서 동일한 키를 사용하는 대칭키 알고리즘
- 2001년 미국 표준 기술 연구소(NIST)에 의해 제정된 암호화 방식
- AES 표준은 여러 Rijindael 알고리즘 중 블록 크기가 128비트인 알고리즘
- ECB(Electronic Code Block)
- 기본 타입, 역추적 가능, 암호화 키 유추 가능
- CBC(Ciper Block Chaining)
- ECB 보완
- 암호화 키에 Initial Vector 추가
- 병렬처리 불가
- GCM(Galois/Counter Mode)
- CBC 보완
- 데이터의 hash가 암호문에 포함 -> 복호화시 변조 확인 가능
- 병렬 처리 가능
RSA-OAEP
OAEP(Optimal Asymmetric Encryption padding)
- RSA는 동일한 키 값을 사용하므로 중간에 암호문을 도청하더라도 해독이 어렵지만 동일한 문자가 사용되었음은 알아챌 수 있다.-> 같은 문자라도 다른 결과가 나오도록 padding을 추가한 것
PKCS
- PKCS는 Public-Key Cryptography Standard로 RSA 시큐리티에서 정한, 공개 키 암호에 대한 사용 방식에 대한 표준 프로토콜
- 공개 키 기반구조, PKI(Public Key Infrastructure)를 기반으로 한 1990년대 초에 RSA Security LLC에서 고안 및 게시판 공개 키 암호화 표준 그룹
JWK(Json Web Key)
- JWK는 암호화 키를 표현하기 위한 다양한 정보를 담은 JSON 객체에 관한 표준이다.
- RFC7517
- 암호화 키를 나타내는(Cryptographic Key) JavaScript Object Notation(JSON) 데이터 구조
- JWKs(JWK의 집합) 도 표현
- key
- kty: key type(RSA EC…)
- key_ops: key option(sign, enc)
- rsa key 구성
- e: rsa exponent(public key에 존재)
- n: rsa modoulus(public key에 존재)
- d: D
- p: P
- q: Q
- dp: exponent1
- dq: exponent2
- qi: coefficient
Python-jose 에서 JWE/JWK 사용 With RSA
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey
from jwt.utils import to_base64url_uint
pri_format = serialization.load_pem_private_key(private_key.encode(), password=None, backend=default_backend())
pub_format = serialization.load_pem_public_key(public_key.encode(), backend=None)
breakpoint()
key = {
"kty": "RSA",
"use": "enc",
"alg": "RSA-OAEP-256",
'e': to_base64url_uint(pub_format.public_numbers().e).decode(),
'n': to_base64url_uint(pub_format.public_numbers().n).decode()
}
key2 = {
"kty": "RSA",
"key_ops": ["enc"],
'd': to_base64url_uint(pri_format.private_numbers().d).decode(),
'p': to_base64url_uint(pri_format.private_numbers().p).decode(),
'q': to_base64url_uint(pri_format.private_numbers().q),
'e': to_base64url_uint(pri_format.public_key().public_numbers().e).decode(),
'n': to_base64url_uint(pri_format.public_key().public_numbers().n).decode(),
'dp': to_base64url_uint(pri_format.private_numbers().dmp1).decode(),
'dq': to_base64url_uint(pri_format.private_numbers().dmq1).decode(),
'qi': to_base64url_uint(pri_format.private_numbers().iqmp).decode()
}
res = jwe.encrypt(plaintext='string'.encode('utf-8-sig'), key=key, algorithm='RSA-OAEP-256', encryption='A128GCM')
res1 = jwe.decrypt(res, key2)
참고 자료