일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- SSH
- MFA
- kmip
- 2FA
- SWIFT
- MYSQL
- 안드로이드
- FIDO2
- css
- otpkey
- SwiftUI
- MSYS2
- OTP
- appres
- openssl
- WebAuthn
- Nodejs
- fido
- 인증
- SSL
- git
- 앱스토어
- Android
- OSX
- Xcode
- albumbook
- 앱리소스
- apple
- 앨범북
- 애플
- Today
- Total
인디노트
Node.js 에서 RSA 로 암복호화 하기 본문
Node.js 의 crypto 모듈은 기본적으로 제공되므로, npm 으로 설치할 필요가 없습니다.
crypto 기본 모듈을 사용해 RSA 의 키로 암복호화 하는 방법을 알아 봅시다.
일단 그 전에 OpenSSL로 RSA Private Key, Public Key 를 생성합니다.
C:\Users\Public>openssl genrsa -out private.key 2048
Generating RSA private key, 2048 bit long modulus
.................................................................................................................................+++
.........+++
unable to write 'random state'
e is 65537 (0x10001)
예전 블로그의 AES 관련 글 을 보시면 아시다시피,
Private key 로 Public key 를 Generate 할 수 있습니다.
C:\Users\Public>openssl rsa -in private.key -out public.key -pubout
그런데 단순히 이렇게 하시면, 결과가 PKCS#8 표준으로 나옵니다.
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuErwCGWyq3nIASTKhgiH
GAaURZ9rs5EBR9L1YUJh1ftYgQSt0gUzab6hyW/upgM4Z4Mu6pA+KZCHncKc4SHJ
XdJvYnj1L6/RRinXQp+R3MmGypoB/r1ckM1aEt75/I0m7Dlatj58f56Z21yHsJNb
tf1LAD981a3kR6kaIb7Uc5bsUDwObF2r5xAenQDtaZoWgaErHWwiqzJJQebcAVVq
lq2/+f1kzRVqHsasosXOD6hrDz9oC2SvBKWVrmOPF4D+mwwaChEKAhFDvCKj5NYw
prmoOXWK6t5WroYvsVo5Sa039DiCPXMsug9MidhQLB7SpW7Bi+xeuwvObWppgGZ8
FQIDAQAB
-----END PUBLIC KEY-----
PKCS#8 표준의 ASN.1 구조를 보면 다음과 같습니다.
PublicKeyInfo ::= SEQUENCE {
algorithm AlgorithmIdentifier,
PublicKey BIT STRING
}
AlgorithmIdentifier ::= SEQUENCE {
algorithm OBJECT IDENTIFIER,
parameters ANY DEFINED BY algorithm OPTIONAL
}
우리는 PKCS#1 을 사용할 것이므로 아래와 같이 변환합니다.
C:\Users\Public>openssl rsa -pubin -in public.key -RSAPublicKey_out
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEAuErwCGWyq3nIASTKhgiHGAaURZ9rs5EBR9L1YUJh1ftYgQSt0gUz
ab6hyW/upgM4Z4Mu6pA+KZCHncKc4SHJXdJvYnj1L6/RRinXQp+R3MmGypoB/r1c
kM1aEt75/I0m7Dlatj58f56Z21yHsJNbtf1LAD981a3kR6kaIb7Uc5bsUDwObF2r
5xAenQDtaZoWgaErHWwiqzJJQebcAVVqlq2/+f1kzRVqHsasosXOD6hrDz9oC2Sv
BKWVrmOPF4D+mwwaChEKAhFDvCKj5NYwprmoOXWK6t5WroYvsVo5Sa039DiCPXMs
ug9MidhQLB7SpW7Bi+xeuwvObWppgGZ8FQIDAQAB
-----END RSA PUBLIC KEY-----
PKCS#1 의 ASN.1 구조는 다음과 같습니다.
RSAPublicKey ::= SEQUENCE {
modulus INTEGER, -- n
publicExponent INTEGER -- e
}
(참고로 반대로 ( PKCS#1 -> PKCS#8 ) 변환하는 하는 방법은 아래와 같습니다.)
openssl rsa -RSAPublicKey_in -in
이제 예제를 볼까요?
RSA encyrpt & decrypt in node.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | var crypto = require( 'crypto' ); var PRIVKEY = '-----BEGIN RSA PRIVATE KEY-----\n' + 'MIIEowIBAAKCAQEAuErwCGWyq3nIASTKhgiHGAaURZ9rs5EBR9L1YUJh1ftYgQSt\n' + '0gUzab6hyW/upgM4Z4Mu6pA+KZCHncKc4SHJXdJvYnj1L6/RRinXQp+R3MmGypoB\n' + '/r1ckM1aEt75/I0m7Dlatj58f56Z21yHsJNbtf1LAD981a3kR6kaIb7Uc5bsUDwO\n' + 'bF2r5xAenQDtaZoWgaErHWwiqzJJQebcAVVqlq2/+f1kzRVqHsasosXOD6hrDz9o\n' + 'C2SvBKWVrmOPF4D+mwwaChEKAhFDvCKj5NYwprmoOXWK6t5WroYvsVo5Sa039DiC\n' + 'PXMsug9MidhQLB7SpW7Bi+xeuwvObWppgGZ8FQIDAQABAoIBAQCPOcYkcI0UETgs\n' + 'E2DGHBiJxoszNLuqOVaKcFw9sy5/87ALzQwdvecAFqR7/d617KjIYb5zk5iMCwQq\n' + 'ylXL7csmfGYOXL0Iy5ZT9i6SW5srwP9ds6U7SgWHj+Ch6+LSsQx/5+8k1ZlCQYuH\n' + 'XPkjdNKAtJK2ZaDqHBPe0YA6m6lXDrEOJl6xrlUWCZS02XPIXFaB+qTBG2UqWCUK\n' + 'KzVa9qIqWf3bVGJCLc70u5UiuvCC+V8VtJ964AEnj90qZy1tRhEc2X8bbWmhL3yB\n' + '3SLWH4ZvJyEDQe/yycx9rO6CymDj3c378IyWORYt1y6mKRmltr2NJ1Ecbl9xaFrc\n' + 'JeVO8wDdAoGBAOUjZzuaVppccEIiBbLS0NksSeD4tfjlUPFqVU1obZcbkDugK1Id\n' + 'og+W5yVy2NqgeEi4nQ9Ogi485cWbCzTZM52d9zuFe/60hBFPU8jWxafW0OW2o6ci\n' + 'F1vtzWEF2EO7omUoiGu6mOI4yRcUMwXiw1cCWr2NYpASQ39QuxwXKgg7AoGBAM3l\n' + 'sC7nxqDusq+J9CI6V+oNb2v7KgapQmrdXNB5l6Mk2Dl/uNfuX5cDceMQlO5B/ObT\n' + '44kgsBR3tO6y7PQLDClt5ZPrVJZ16+cCj41UDDgZDD0vDaU24K/qSVrsOH4gNgeM\n' + 'CcsInzX/l1bm+RAhE0pHuPHBZFuLi8brV/wZCpfvAoGAQu4XbmKDn20W4UpczcIk\n' + 'fPshzVP4m24oOYwsxIKXWEcV10TOwpqjRth2RgsI6rtqxxsdzWXKQsVI/HJwUIyN\n' + 'NiH5IGq6MEj8Nq4sNAMAEyl9NUwm+1/K4PBSSF/Trt0070Vqq8UCeTnLCzG8QaDe\n' + 'HCE07h9JRfn/u0WSkf72KRcCgYAUTGmjJix53y50idgsq63RIEP01E0fXP50RKCK\n' + '2QHvDonWmVXiy9hWrftDVHYqSw0gwJD1CujxC6AlzDP6F0C6sN/qRlAPiU6ZdrIq\n' + 'T7foq+d9/K6OtCtQjHtw4ErtfEV3VwH8Jzxy+WC1K44wXeJl904vX06Ci+5azQbe\n' + 'jqVxtwKBgBnxVKFQCmuDjOZrf7V0jB/mf4ir9npqvHdJMHE/Et70lOaUbhat6i+Y\n' + 'PPtJewynfF4zp+HD6jOlj4RhbCncMNdaWAyDYOucYOJOpMr5mIYJHdCOVQ0aSRD7\n' + '/dZEOGblrch6VXOEvC++yaToNhjkeTP63IH4K6uqa9btelz3Df5Y\n' + '-----END RSA PRIVATE KEY-----\n' ; var PUBKEY = '-----BEGIN RSA PUBLIC KEY-----\n' + 'MIIBCgKCAQEAuErwCGWyq3nIASTKhgiHGAaURZ9rs5EBR9L1YUJh1ftYgQSt0gUz\n' + 'ab6hyW/upgM4Z4Mu6pA+KZCHncKc4SHJXdJvYnj1L6/RRinXQp+R3MmGypoB/r1c\n' + 'kM1aEt75/I0m7Dlatj58f56Z21yHsJNbtf1LAD981a3kR6kaIb7Uc5bsUDwObF2r\n' + '5xAenQDtaZoWgaErHWwiqzJJQebcAVVqlq2/+f1kzRVqHsasosXOD6hrDz9oC2Sv\n' + 'BKWVrmOPF4D+mwwaChEKAhFDvCKj5NYwprmoOXWK6t5WroYvsVo5Sa039DiCPXMs\n' + 'ug9MidhQLB7SpW7Bi+xeuwvObWppgGZ8FQIDAQAB\n' + '-----END RSA PUBLIC KEY-----\n' ; // RSA PRIVATE ENCRYPT -> PUBLIC DECRYPT // myMSG = "[ORIGINAL] I'm securekim !!!" ; function privENC_pubDEC(originMSG){ encmsg = crypto.privateEncrypt(PRIVKEY, Buffer.from(originMSG, 'utf8 ') ).toString(' base64 '); msg = crypto.publicDecrypt(PUBKEY, Buffer.from(encmsg, ' base64 ')); console.log("Encrypted with private key : "+encmsg); console.log(msg.toString()); } function pubENC_privDEC(originMSG){ encmsg = crypto.publicEncrypt(PUBKEY, Buffer.from(originMSG, ' utf8 ') ).toString(' base64 '); msg = crypto.privateDecrypt(PRIVKEY, Buffer.from(encmsg, ' base64')); console.log( "\nEncrypted with public key : " +encmsg); console.log(msg.toString()); } privENC_pubDEC(myMSG); pubENC_privDEC(myMSG); |
- 결과 :
Encrypted with private key : Q9Tz2LRlv91Rk2ScR/Wjv77ouDsiWyefVIKlssIYHBJihZeQ0IDH+rUCMG0aBhSDNT92zZjAmPF5Pah9xejqYsfCfDslmNp+FXvmfoA02uviW6b4A6e90U3atyU1PIZHtp4nDtIAYCvY78xzEyZ5oqwhbDcKuIcs4Uo4dtXNmo6N9/+Rxckf0ByCyRAUv86x1a6SYzgqyGthaDAnIUxFAXsJpAkrAOTeBy9PKx785DEXYDBOzgsFcZRHwMuFNFlMTYfQtW/rwPL0cSA6ud3Ew0Qsv4wY73ty46s2kYezSo6YjrHkYDotlhXLK5rqY+bBtU/SAufvhj/BDxYEDe9scQ==
[ORIGINAL] I'm securekim !!!
Encrypted with public key : CEhDVj/6KquMN5QRi69okZXz6gVjHKQGOm1C1CvBExRTQrKN8sMMT1wqTQpRdVzu+YUlidgCmj+v+5bgiSMl1Ul38VUHT9rL42fwT226RYfhlMvRn2umddboyHh0TMPwWqI6aQ/36DQqmuXN34Rk2It2qs5gERZWTJgRdQ1mYrrz7nOA5nnu/vZyOmk4PjYww9QediUF+J9pxOAlYsIT+AdOXVvdKeB6M5esGZWwQ3trZvklG0KmZSNUQ6HyvQ/+MorsKDMOZxpRcBxTB+3DzzUb+UtvBSlsUNYfnMAYlEeB7M4AzgIJpZ8jfYOecp9DSx6eTzk919YVCyUU3GL2oQ==
[ORIGINAL] I'm securekim !!!
일반적으로 각 함수가 사용되는 용도는 다음과 같습니다.
ㆍprivENC_pubDEC
- Signature Verify
예를 들어 상호 인증시 클라이언트는 이때까지 주고받은 내용을 Hash 한 다음
Private key 로 암호화해 Signature 를 생성해 서버로 전달합니다.
서버는 이때까지 주고받은 내용을 Hash 한 값과,
클라이언트가 보내준 인증서의 Public key로 Signature 를 복호화 한 값을 비교하여
동일한지 판단 합니다.
ㆍpubENC_privDEC
- AES KEY nego
클라이언트가 AES Key 를 서버의 Public key 로 암호화해서
서버에게 전달 해 주면 서버에서는 복호화 합니다.
이렇게 하여 클라이언트와 서버는 AES Key 를 나눠갖게 되고,
이후 통신을 AES KEY 로 암호화 하는 이유는 RSA 암호화 방식은 AES 에 비해 너무 느리기 때문입니다.
그리고 메시지의 길이가 긴 경우 아래와 같이 RSA 로 암호화가 되지 않습니다.
Error: error:0406C06E:rsa routines:RSA_padding_add_PKCS1_type_1:data too large for key size
다음 포스팅에서는 Node.js 에서 crypto 모듈을 사용해 AES 암호화를 해보겠습니다.
'인증기술' 카테고리의 다른 글
공인인증서에서 개인키 획득하기 (using C#) (0) | 2018.06.18 |
---|---|
Cipher Suites and Enforced Strong Security (0) | 2018.05.07 |
[Kisa] 암호의 이해와 키 관리 실무 - IOT 보안 (0) | 2018.05.05 |
[Kisa] 암호의 이해와 키 관리 실무 - FIDO (0) | 2018.05.05 |
[Kisa] 암호의 이해와 키 관리 실무 - 4일차 암호와 금융 보안 (0) | 2018.05.05 |