프로젝트를 진행하면서 Issuer가 발급한 Verifiable Credential을 암호화해야 하는 상황이 생겼다. JWT를 이용해서 암호화 복호화 하는 방향으로 정하고, 비대칭키 방법을 적용했다. 기존에 JWT는 대칭키로만 사용해서 서버에서 인증용도로만 사용했었는데, VC를 암호화하는 방식으로 사용하는 건 이번이 처음이다.
JWT 비대칭키
비대칭키를 생성하는 알고리즘은 여러가지가 있지만, 이번 경우에는 Node.js에서 기본 제공되는 crypto 모듈을 사용해 RSA 알고리즘, pem 형식으로 비대칭키를 발급받아 publicKey와 privateKey로 사용했다.
우선 crypto module로 비대칭키를 발급받는 방법은 아래 글을 참고하면 된다.
비대칭키 Pairs를 발급받은 후 JWT로 암호화 복호화를 진행한다. Node.js crypto 모듈로 발급받은 비대칭키는 RSA 알고리즘을 사용하므로, JWT에서 암/복호화를 하기 위해서는 Algorithm을 명시해줘야 한다. Algorithm의 기본값이 HS256이기 때문이다.
JWT 암호화
비대칭키를 우선 생성한다.
const genKey = () => {
try {
const { publicKey, privateKey } = generateKeyPairSync("rsa", {
modulusLength: 4096,
publicKeyEncoding: {
type: "spki",
format: "pem",
},
privateKeyEncoding: {
type: "pkcs8",
format: "pem",
cipher: "aes-256-cbc",
passphrase: "top secret",
},
});
return { publicKey, privateKey};
} catch (error) {
console.log(error)
}
};
암호화에 사용되는 PrivateKey는 추가적으로 다시 생성해줘야 한다. pem 형식으로 기존에 발급된 privateKey가 아니라 Object 형식으로 반환되는 Key를 사용해 암호화가 가능하다.
암호화에 사용할 Key를 생성하는 함수를 하나 만들어 주고,
const genPrivateKey = (k) => {
const key = crypto.createPrivateKey({
key: k,
format: "pem",
passphrase: "top secret",
});
return key;
};
Issuer로 부터 발급된 VC를 암호화한다.
const key = genPrivateKey(privateKey);
// JWT Sign (개인키로 암호화)
const messageSign = jwt.sign(
{
sub: "did:klay:0x435df3eda57154cf8cf7926079881f2912f54db4",
nbf: 1562950282,
vc: {
"@context": ["https://www.w3.org/2018/credentials/v1"],
type: ["VerifiableCredential"],
credentialSubject: {
degree: {
type: "BachelorDegree",
name: "Baccalauréat en musiques numériques",
},
},
},
},
key,
{
issuer: "AboutTech",
algorithm: "RS256",
}
);
3번째 인자로 만료기간, 알고리즘, 발행자 등을 명시할 수 있는데, alogorithm에 RS256을 지정해준다. 암호화된 Message를 출력하면 다음처럼 나온다.
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6a2xheToweDQzNWRmM2VkYTU3MTU0Y2Y4Y2Y3OTI2MDc5ODgxZjI5MTJmNTRkYjQiLCJuYmYiOjE1NjI5NTAyODIsInZjIjp7IkBjb250ZXh0IjpbImh0dHBzOi8vd3d3LnczLm9yZy8yMDE4L2NyZWRlbnRpYWxzL3YxIl0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiXSwiY3JlZGVudGlhbFN1YmplY3QiOnsiZGVncmVlIjp7InR5cGUiOiJCYWNoZWxvckRlZ3JlZSIsIm5hbWUiOiJCYWNjYWxhdXLDqWF0IGVuIG11c2lxdWVzIG51bcOpcmlxdWVzIn19fSwiaWF0IjoxNjYyNTE5MTE3LCJpc3MiOiJBYm91dFRlY2gifQ.X9TFCpirMWZF6rpgKKAJ4exoN0wxvEXDueZC-InA6D67YBH2gJYCz7FbWCug7SCCYJL6r1h9vBtxdgU390L-FpBIiP5oxkmpf8C8OOwZX3w_hyAhjWynnrP2s8Dv0zsNJJH1DMgIa3QOwudi-dOl1xavp6Wq2tzOXVf_ZecQLH-Ik1sHjQTNR9kNcVmh57bD9UQvPcPpa3EQXxhYGnSBTjAZJpDZiqsPWI8jo6qeQwvFDVpDxY4XGsHU6h_bBxNuhsvYpNflhtvxDfR9Czo4EQNf7a3SH7gWICKUi7fxzKrDN2m9PX7CF0jOs6LGm0UZ7RrOYsshVO8fBKFCh4dRFtgiDvxyYbhwC5tWsXJfO9vo7e14Yz5c0i_S0UgsYyd6tInfp9lSaQ-UoOvZlOOM5yKNwnEGcHxWTqGKZFbrWfBXhKLAc9FtjODc2CXFx3hrRJ8x50a61Iet2iwZL0UXNNrLRiZzKvC0pYeA4fXvJAeEvpOWRCF5MbCa9DUXv4wXTpM75d-t1BFzdFYiV6X5mJYTwjWGsUMG2Xop9cgavEtyNFokcR0IqZotUeGe4HS6Rvx9l3CY59Ubkl-rdxIUslKAafkVhsvGB_p73G5A1Dt8-J8tfxpLLQZFt_BlQY4aekewdZPxm6hpEqJo99xaUGRKsegmeNe_WAPO60YMQPw
JWT 복호화
비대칭키를 사용해 암/복호화를 진행하므로, 암호화는 PrivateKey를 사용했지만 복호화에는 PublicKey를 사용한다.
const verifiedMessage = jwt.verify(messageSign, pubKey);
복호화를 진행하면 JWT payload에 담았던 정보가 그대로 출력된다.
더 알아볼 내용
문제는 Key Pair을 생성하는 방법과 어떻게 안전하게 관리할 것인가에 대한 다음 step이 남아있다. did-jwt-vc 모듈을 사용하면 DID Resolver에서 DID Document를 가져와서 pubkey를 추출해 복호화 하는 로직을 지원한다. 즉, wallet의 secret Key값과 주소값으로 암복호화가 가능한데, baobab 테스트 환경에서 사용자의 secret값을 입력받는 로직은 사용자의 거부감을 일으킬 수 있어 제작을 하지 못했다.
또한 지갑 주소와 지갑 시크릿 값을 사용해 암복호화 하는 방법을 찾아보면 Klip에서 QR 코드를 찍는 방식으로 시크릿 값을 가져와 암/복호화 하는 방식을 사용할 수도 있겠다.
'Programming' 카테고리의 다른 글
[회고록] 코드스테이츠 프로젝트 DID 인증 서비스의 가치는? (0) | 2022.09.15 |
---|---|
와이어샤크 우분투 설치 사용 방법 (0) | 2022.09.07 |
Node.js event eventEmitter 란? 이벤트 처리하기 (0) | 2022.09.06 |
개발 공부 하기전 알면 좋은 것들 회고록 (0) | 2022.09.05 |
Node.js file System 폴더 파일 지우기 폴더 내용 확인하기 (0) | 2022.09.04 |
댓글