Web Crypto API: RSA 개인 키로 해독

소개



브라우저측은 RSA의 공개열쇠키로 암호화해, 서버측(Node.js)은 프라이빗 키로 복호를 시도하면, 이하의 에러가 발생해, webcrypto 모듈을 사용해 해소할 수 있었습니다.

Error: error:04099079:rsa routines:RSA_padding_check_PKCS1_OAEP_mgf1:oaep decoding error
at Object.privateDecrypt (internal/crypto/cipher.js:53:12)

Web Crypto API란?



사양 요약 페이지 : htps : //로 ゔぇぺぺr. 모잖아. 오 rg / 그럼 / cs / u b / ap / u b_Cryp 및 _ Api
페이지에 있는 경고에 따라 신중하게 대응해야 합니다.


출처 : htps : //로 ゔぇぺぺr. 모잖아. 오 rg / 그럼 / cs / u b / ap / u b_Cryp 및 _ Api

Web Crypto API 주요 메소드



Window.crypto 또는 crypto 객체에서 SubtleCrypto라는 인터페이스에서 여러 메서드를 확인할 수 있습니다.


SubtleCrypto


  • SubtleCrypto.encrypt(): 암호화
  • SubtleCrypto.decrypt() : 복호
  • SubtleCrypto.sign() : 서명
  • SubtleCrypto.verify() : 서명 검증
  • SubtleCrypto.digest() : 다이제스트 생성
  • SubtleCrypto.generateKey() : 키 생성
  • SubtleCrypto.deriveKey() : 마스터 키와 알고리즘에 의해 새로운 CryptoKey를 파생
  • SubtleCrypto.deriveBits() : 마스터 키와 알고리즘에 의해 의사 난수 비트의 새롭게 생성된 버퍼를 생성
  • SubtleCrypto.importKey() : 공개키, 프라이빗 키 등으로부터 CryptoKey를 생성
  • SubtleCrypto.exportKey() : 키를 Export
  • SubtleCrypto.wrapKey():래핑된 키
  • SubtleCrypto.unwrapKey () : 래핑 된 키로부터 CryptoKey를 생성합니다.

    의사 난수 생성: Crypto.getRandomValues



    대칭 암호화의 IV 생성에 필요한 의사 난수 생성 메소드도 자주 사용하는 메소드입니다.
    typedArray = cryptoObj.getRandomValues(typedArray);
    

    사용 예:
    var array = new Uint32Array(10);
    window.crypto.getRandomValues(array);
    

    결과:


    지원되는 알고리즘





    출처 : htps : //로 ゔぇぺぺr. 모잖아. 오 rg / Enu S / Docs / Ue b / Api / Su bt Cryp

    브라우저측: 공개키로 암호화



    공개키로 암호화에는 공개키의 임포트와 암호화의 2개의 수속이 있습니다.
    ・공개키의 임포트:SubtleCrypto.importKey()
    const result = crypto.subtle.importKey(
        format, // raw(AESの鍵),pkcs8(RSAのプライベート鍵),spki(SubjectPublicKeyInfo:RSAまたはElliptic Curveの公開鍵),jwk(JSON Web Key)
        keyData, // キーデータ。ArrayBuffer、TypedArray、JSONWebKeyオブジェクト
        algorithm, // ①、RsaHashedImportParams :RSA-OAEP、RSA-PSS。②、EcKeyImportParams:ECDSA、ECDH。③、HmacImportParams :HMAC ④、{ "name": ALGORITHM }:AES-CTR, AES-CBC, AES-GCM、AES-KW。 ⑤、PBKDF2
        extractable, // true/false。 SubtleCrypto.exportKey() or SubtleCrypto.wrapKey()メソッドを使うか
        usages // ["encrypt", "decrypt", "sign", "verify", "deriveKey", "deriveBits", "wrapKey", "unwrapKey"]
    );
    

    공개 키 가져 오기 예제 (htps : //로 ゔぇぺぺr. 모잖아. 오 rg/쟈/도cs/우ぇb/아피/스 btぇCryp와/이 m포 rt케 y):
     // from https://developers.google.com/web/updates/2012/06/How-to-convert-ArrayBuffer-to-and-from-String
      function str2ab(str) {
        const buf = new ArrayBuffer(str.length);
        const bufView = new Uint8Array(buf);
        for (let i = 0, strLen = str.length; i < strLen; i++) {
          bufView[i] = str.charCodeAt(i);
        }
        return buf;
      }
    
      const pemEncodedKey = `-----BEGIN PUBLIC KEY-----
    .......
    -----END PUBLIC KEY-----`;
    
      function importRsaKey(pem) {
        const pemHeader = "-----BEGIN PUBLIC KEY-----";
        const pemFooter = "-----END PUBLIC KEY-----";
        const pemContents = pem.substring(pemHeader.length, pem.length - pemFooter.length);
        // base64 decode the string to get the binary data
        const binaryDerString = window.atob(pemContents);
        // convert from a binary string to an ArrayBuffer
        const binaryDer = str2ab(binaryDerString);
    
        return window.crypto.subtle.importKey(
          "spki",
          binaryDer,
          {
            name: "RSA-OAEP",
            hash: "SHA-256"
          },
          true,
          ["encrypt"]
        );
      }
    

    ※SubtleCrypto.generateKey()로 생성하는 것도 가능합니다만, 일반적으로 먼저 OpenSSL등 사전에 생성한 공개키를 임포트한다고 생각됩니다.

    · 암호화 : SubtleCrypto.encrypt()
    function encryptMessage(publicKey, message) {
      let enc = new TextEncoder();
      let encoded = enc.encode(message);
      return window.crypto.subtle.encrypt(
        {
          name: "RSA-OAEP"
        },
        publicKey,
        encoded
      );
    }
    

    서버 측 (Node.js) : 개인 키로 해독



    복호에는 프라이빗 키의 임포트, 복호의 2개의 수속이 있습니다.

    Node.js의 Crypto 모듈을 사용하고 싶지만 해독 할 수 없습니다.
    htps : // 그래서 js. ORG / API / CRYP. html # cryp와 _ cryp와 _ p rip에서 crypt_p rip teke y_bup r

    @peculiar/webcrypto를 사용하여 해독 할 수있었습니다.
    webcrypto: htps : // 기주 b. 코 m / ぺ ぃ r

    · 개인 키 가져 오기 : SubtleCrypto.importKey ()

    node.js
    const webcrypto = require("@peculiar/webcrypto");
    const crypto = new webcrypto.Crypto();
    const {TextDecoder} = require('util');
    
    const pemText = "xxxxx";
    const pkcs8 = Buffer.from(pemText, "base64");
    const key = crypto.subtle.importKey("pkcs8", pkcs8, { name: "RSA-OAEP", hash: "SHA-256" }, true, ["decrypt"]);
    

    ・복호:SubtleCrypto.decrypt()

    node.js
    const decryptedStr = await crypto.subtle.decrypt("RSA-OAEP", key, Buffer.from(encryptedMessage, "base64"));
    const result = new TextDecoder("utf-8").decode(new Uint8Array(decryptedStr ));
    

    참고 : h tps : // s t c ゔ ぇ rf ぉ w. 코 m / 쿠에 s chion s / 56058153 / r-s-cryp chion-u th-cryp와 - Mozu-Gi ゔ ぇ s r-o-p 512

    기타: 대칭 암호화 예(AES-GCM)


    function encryptMessage(key, message) {
      let enc = new TextEncoder();
      let encoded = enc.encode(message);
      iv = window.crypto.getRandomValues(new Uint8Array(12));
      return window.crypto.subtle.encrypt(
        {
          name: "AES-GCM",
          iv: iv
        },
        key,
        encoded
      );
    }
    
    

    이상
  • 좋은 웹페이지 즐겨찾기