diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..bf357fb --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,3 @@ +{ + "trailingComma": "all" +} diff --git a/.vscode/settings.json b/.vscode/settings.json index 521eda4..a08982f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,7 +1,5 @@ { - "deno.enableFormatter": true, - "editor.formatOnSave": true, - "editor.tabSize": 2, - "deno.enable": true, - "files.eol": "\n" -} \ No newline at end of file + "editor.tabSize": 2, + "deno.enable": true, + "files.eol": "\n", +} diff --git a/src/rsa/basic_encoding_rule.ts b/src/rsa/basic_encoding_rule.ts index a2d9833..c2fda24 100644 --- a/src/rsa/basic_encoding_rule.ts +++ b/src/rsa/basic_encoding_rule.ts @@ -55,10 +55,7 @@ function ber_integer(bytes: Uint8Array, from: number, length: number): bigint { } function ber_oid(bytes: Uint8Array, from: number, length: number): string { - const id = [ - (bytes[from] / 40) | 0, - (bytes[from] % 40), - ]; + const id = [(bytes[from] / 40) | 0, bytes[from] % 40]; let value = 0; for (const b of bytes.slice(from + 1, from + length)) { @@ -125,7 +122,7 @@ function ber_next( } return { - totalLength: (ptr - from) + size, + totalLength: ptr - from + size, type, length: size, value, diff --git a/src/rsa/import_key.ts b/src/rsa/import_key.ts index a8078c2..10e60ab 100644 --- a/src/rsa/import_key.ts +++ b/src/rsa/import_key.ts @@ -94,6 +94,33 @@ function rsa_import_pem_private(key: string): RSAKeyParams { }; } +/** + * Import private key from Privacy-Enhanced Mail (PEM) format + * https://tools.ietf.org/html/rfc5208 + * + * @param key PEM encoded key format + */ +function rsa_import_pem_private_pkcs8(key: string): RSAKeyParams { + const trimmedKey = key.substr(27, key.length - 57); + const parseWrappedKey = ber_simple( + ber_decode(base64_to_binary(trimmedKey)), + ) as [number, unknown, Uint8Array]; + + const parseKey = ber_simple(ber_decode(parseWrappedKey[2])) as bigint[]; + + return { + n: parseKey[1], + d: parseKey[3], + e: parseKey[2], + p: parseKey[4], + q: parseKey[5], + dp: parseKey[6], + dq: parseKey[7], + qi: parseKey[8], + length: get_key_size(parseKey[1]), + }; +} + /** * Import public key from Privacy-Enhanced Mail (PEM) format * https://tools.ietf.org/html/rfc5208 @@ -124,6 +151,7 @@ function rsa_import_pem(key: string): RSAKeyParams { const maps: [string, (key: string) => RSAKeyParams][] = [ ["-----BEGIN RSA PRIVATE KEY-----", rsa_import_pem_private], + ["-----BEGIN PRIVATE KEY-----", rsa_import_pem_private_pkcs8], ["-----BEGIN PUBLIC KEY-----", rsa_import_pem_public], ["-----BEGIN CERTIFICATE-----", rsa_import_pem_cert], ]; diff --git a/tests/rsa/rsa.import_key.test.ts b/tests/rsa/rsa.import_key.test.ts index 7b11fbd..6c6a6e8 100644 --- a/tests/rsa/rsa.import_key.test.ts +++ b/tests/rsa/rsa.import_key.test.ts @@ -3,13 +3,12 @@ import { assertEquals } from "https://deno.land/std@0.63.0/testing/asserts.ts"; Deno.test("RSA - Import JWK Public Key", () => { const jwk = { - "e": "AQAB", - "alg": "RS256", - "use": "sig", - "n": - "7NfiTQcshWgrEdKbHC2e1s92kK-YX7jS3JLFIBpT8f_j_b5y3dQdtFFS4vBoVNQkwep_34x_ihYlhA3QkwaTL2XMSiedjLnubFZBUjs7G0dgGIR3F8A06Bf5KT4g2x1dKVb0Lwwqg22XIfqaS88HdU5pDwcVmq4pVMaJQgUK-xFEC_sHdfqTV8Z0uBCr9Nik_7xz68FINDYyLhehnvwph9ui-8_WeDgU_h5xrG8H7oY28y2NCtBwXxIadB-K8pHxK2srM8wTCIivdyZS80P0jZMqyxPkt4fO33-GQWvelVmR0bS4Arb3Y4bXnoAMCEao3DTm0bgeNVz39274ippJSQ", - "kty": "RSA", - "kid": "0a7dc12664590c957ffaebf7b6718297b864ba91", + e: "AQAB", + alg: "RS256", + use: "sig", + n: "7NfiTQcshWgrEdKbHC2e1s92kK-YX7jS3JLFIBpT8f_j_b5y3dQdtFFS4vBoVNQkwep_34x_ihYlhA3QkwaTL2XMSiedjLnubFZBUjs7G0dgGIR3F8A06Bf5KT4g2x1dKVb0Lwwqg22XIfqaS88HdU5pDwcVmq4pVMaJQgUK-xFEC_sHdfqTV8Z0uBCr9Nik_7xz68FINDYyLhehnvwph9ui-8_WeDgU_h5xrG8H7oY28y2NCtBwXxIadB-K8pHxK2srM8wTCIivdyZS80P0jZMqyxPkt4fO33-GQWvelVmR0bS4Arb3Y4bXnoAMCEao3DTm0bgeNVz39274ippJSQ", + kty: "RSA", + kid: "0a7dc12664590c957ffaebf7b6718297b864ba91", }; const key = RSA.importKey(jwk); @@ -49,3 +48,46 @@ Deno.test("RSA - Import Certificate PEM", () => { ); assertEquals(key.length, 256); }); + +Deno.test("RSA - Import Private Key (PKCS8)", () => { + const raw = `-----BEGIN PRIVATE KEY----- + MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCVZ6og4XGxLAHH + ZwHm27AtUMP6+8wFqllvup0Tr0V21YvxzPxWjav2+mLOIM8upa7pzvcpc5EiCH58 + denmLJsygqo0r2B8WhzHY+rCIWJfV2YSZxjzpvSAHfzLJrDphXgqgnCNxEjRsuyC + YAiGLIMK0huY90A5MMMArgUzkx8kMd/fq/Gd9Xt5iI+F7NlylJ+arnJc306pgGHK + 3NN2GBX1vnSuCB280SUXkZfTBeykyDZ6YrAq0XpnCNV9JyHqLQ4EmjEhc2yUo3aN + RyXNMBddZx3HCLFcxwZCVAp0tQkAd7ErsUD5P5DR8RIJ3frklSUUZB6EkDw8G7KL + WKVcNQ2FAgMBAAECggEABVqkmOQ4s2PzlgkDDdofxJFL+KhXMyPGlo+uNd32hA/v + 4YTaTSLAv8t7c3jEW/RW4ezyDrj5bD9i2FnPEu8pyk6u7qTon67eBaeMapO7h1Wl + 5DEazo5+3WwrBT+4ICI8QG+8vK6E+ojU23DkFU+D4a/OX+C1GzzmsWqgZ+z/inKL + aMwS6rsWROUlgA1x5zNSoqC3SJFllVXXew5UyANTsBjvQ5J2Mmb9g8CEaAOn+xMk + xNlwTlDot+09nFJ9vvAWirUkZdsYNnlY+zrDQoPT7Am5jtKTHmMI1KfWNfmznyji + RltdnWfd8Bg0H7VtwrhWMWGs8QkATUAE+fC3qS144QKBgQDNFLk8eMwK6koMoNmY + vsRAf1Y6Xdd+LUN+TJqkZiUEySaKy8NLi71IBbzK7zKqbYXDPUFCbNJFhOlluKOw + bsKPkwBjR0JfoXVzbUdE+2tM2YccswaJe7iinZxr0wHGXIvJL0HNVIzmNggS7+Zm + rEsdCyFXnTT/83o1wVW3E/lspQKBgQC6gBVyYCP7AxYHTSRDCgcpsTO7HyzuY92t + aYOhRJFC7HNbzJbVdVsfnbtQH/Epe8ySk91GyFZ1dSJrxetcLhHsS2TMrkYUmY4x + bJnqzJTh7cgWBP9DuWYvSJxPooSpFwbh2L12vQ2ADpwwoAZMLkAagaGlY9MZz821 + XY+KkOLnYQKBgQCQ49lTTgzqkUirz2Cst+qznsNvDSnYbWZH7xs6lygET5E5cmiS + ETIzlkoiHgjvu91LaRWYNoYAs7yqL18Godo30aXufkP4iHwQht5ZcEAI1Y7NyfYO + YCi8SxpeW3/fgzcHdqnIxbmeVAI0TuW7GHMhG+H8oob1ZjGrlOJYLHaGOQKBgDLO + vgkAxAyYFKI8k8pnqvfivJMXtSfksPmTKzb99QzkWbEClXzlkcOVNvhnG04P2fV8 + ruWfol4xYQU3UB02t89F4toYCCOIicJRMcVToqPCIaZOCjSrB3mOMHdJcRaXnVpd + r4/vhQQD9u0QS2bpmrEd66mg/lujzwi/ymEXg5lBAoGAacrPblD+G/DAmTUt3tZw + GLdIvw4BeDyCvzxkJx1Z04rMZH71EEyBDPMBByZNPtjpTuzgAZE71MiD3BVLxj/H + dqEjUVQSjuOUyiJKe5GiGF25Xhe3/1VawurCdHfrv6Xmze+lRDHZuEOcV1FrM+zn + KQXlkpPbL3lU2CpgGFFKlFU= + -----END PRIVATE KEY-----`; + + const key = RSA.importKey(raw); + assertEquals(key.e, 65537n); + assertEquals( + key.n, + 18860626341786571281488823024986320858450594409825894653370543036132043241142573896042059032222842653925236802058387508300831766517210547599910735316414515960981281788934868325895562621846910598716519620622800765932541992515497122274302135166053720433521886017494719475895327062855822141735315456613329660043977602681873027347568355824008701177948209784908095092287571982104446342906805480285143028837509076748632094733769028381835899214426100089454654381383340292544225149266603150745375542089871264998183586873913491071542891188124185517417658034185267204900711933432911892469528812455677450346478816563776340692357n, + ); + assertEquals( + key.d, + 675889233296421535959584534071325460876697008626327098961835826056666939623318583538247287416696388446697983317835135300723690022117970081796395234018582764098060974026823771341271141202058228435371968592820841644512299636165137501280011132877728106486853881053264668544941537620562475421678333757690909726581512579603702598150422421865490996288244127528474781858718770957987603681469839575489191876915053252047160475432784849252000744700939988583801783684487872676506769116621572018367654125765915215495461243190782913460732307866572233187464540482209385816659449697777403383908159076257721991916366849321145825505n, + ); + assertEquals(key.length, 256); +});