{"id":15286989,"url":"https://github.com/ngnjs/libcrypto","last_synced_at":"2025-04-13T02:32:45.817Z","repository":{"id":57130676,"uuid":"421238278","full_name":"ngnjs/libcrypto","owner":"ngnjs","description":"A simple cryptography library for NGN","archived":false,"fork":false,"pushed_at":"2024-06-22T08:16:19.000Z","size":130,"stargazers_count":6,"open_issues_count":1,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-10-15T16:45:17.893Z","etag":null,"topics":["browser","crypto","cryptography","decrypt","decryption","deno","ecdsa","encrypt","encryption","hotp","nodejs","rsa","sign","totp","verify"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ngnjs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":".github/CODE_OF_CONDUCT.yml","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":".github/SUPPORT.md","governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["ngnjs","coreybutler","gbdrummer"]}},"created_at":"2021-10-26T01:23:05.000Z","updated_at":"2024-06-22T08:16:22.000Z","dependencies_parsed_at":"2024-09-20T17:41:07.499Z","dependency_job_id":null,"html_url":"https://github.com/ngnjs/libcrypto","commit_stats":{"total_commits":65,"total_committers":2,"mean_commits":32.5,"dds":"0.16923076923076918","last_synced_commit":"f19714ecb61c7748ddff4cc07c88ce1f9aa0677b"},"previous_names":[],"tags_count":11,"template":false,"template_full_name":"ngnjs/.github","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ngnjs%2Flibcrypto","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ngnjs%2Flibcrypto/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ngnjs%2Flibcrypto/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ngnjs%2Flibcrypto/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ngnjs","download_url":"https://codeload.github.com/ngnjs/libcrypto/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248657824,"owners_count":21140842,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["browser","crypto","cryptography","decrypt","decryption","deno","ecdsa","encrypt","encryption","hotp","nodejs","rsa","sign","totp","verify"],"created_at":"2024-09-30T15:20:12.541Z","updated_at":"2025-04-13T02:32:45.507Z","avatar_url":"https://github.com/ngnjs.png","language":"JavaScript","readme":"\u003ch1 align=\"center\"\u003eNGN Cryptography Library\u003cbr/\u003e\u003cimg src=\"https://img.shields.io/npm/v/@ngnjs/libcrypto?label=%40ngnjs/libcrypto\u0026logo=npm\u0026style=social\"/\u003e\u003c/h1\u003e\n\u003cdiv align=\"center\"\u003e\u003cem\u003eA standalone library, but part of the \u003ca href=\"https://github.com/ngnjs/ngn\"\u003eNGN\u003c/a\u003e ecosystem.\u003c/em\u003e\u003c/div\u003e\u003cbr/\u003e\n\nLive examples on [codepen](https://codepen.io/coreybutler/pen/mdMwQQb).\n\nThe NGN crypto library provides simple cryptographic building blocks:\n\n1. Generate RSA or ECDSA Private/Public Keypairs (PEM)\n1. Sign \u0026 Verify Content (using PEM keys) - Not yet supported by Deno\n1. Encrypt/Decrypt Content (AES)\n1. One Time Passwords (HOTP/TOTP)\n1. Generate/Verify JSON Web Tokens (JWT)\n\nAll keys, signatures, and encrypted outputs are Base64 encoded strings (not hex!). Base64 is approximately 25% more efficient than hex (Base16), so the output will be smaller.\n\n## Generate PEM Keypairs\n\nNGN crypto can generate RSA or ECDSA (EC) private and public keypairs.\n\n```javascript\n// Browser/Deno Runtime\nimport crypto from 'https://cdn.jsdelivr.net/npm/@ngnjs/crypto'\n// Node Runtime\n// import crypto from '@ngnjs/crypto'\n\n// RSA Keypairs default to 2048-bit encryption using SHA-256\n// The first argument is the bit and the second is the hash algorithm.\nconst { privateKey, publicKey } = await crypto.generateRSAKeyPair()\nconst { privateKey, publicKey } = await crypto.generateRSAKeyPair(4096, 'SHA-512')\n\n// This is the same as crypto.generateRSAKeyPair()\nconst { privateKey, publicKey } = await crypto.generateKeys()\n\n// ECDSA (EC) Keypairs use a named curve, defaulting to P-256\nconst { privateKey, publicKey } = await crypto.generateECDSAKeyPair()\nconst { privateKey, publicKey } = await crypto.generateECDSAKeyPair('P-521')\n\n// This is the same as crypto.generateECDSAKeyPair()\nconst { privateKey, publicKey } = await crypto.generateECKeyPair()\n```\n\nPublic/Private keys are generated in PEM format.\n\n## Sign \u0026 Verify Content\n\nIt is possible to sign and verify content using RSA/ECDSA keypairs in the browser and Node.js. Deno does not yet support the proper WebCrypto algorithms for importing keys, but it is on their roadmap. Once Deno adds support, this library will support signing/verifying in Deno.\n\nSigning/verification currently uses RSA keys. ECDSA support may be available in some browsers and newer versions of Node.js (17.0.0+).\n\n```javascript\nconst { publicKey, privateKey } = await crypto.generateKeys()\nconst content = 'crypto makes things safe'\nconst signature = await crypto.sign(content, privateKey)\nconst verified = await crypto.verify(content, signature, publicKey)\n```\n\nIn the example above, a private key is used to sign content. This produces a signature, which can be transmitted alongside the content. The receiver of the content uses the signature and their public key to verify the content.\n\nA common use case for signing/verification is API data delivery. The private key is stored on the server, while the public key is delievered to the client. When the client requests data, the server signs the data with the private key, producing a signature. The data is sent as the response body and the signature is usually included as an HTTP response header. When the client receives the response, the body is verified using the public key and the signature. If verification succeeds, the client can be confident the data came from the appropriate server.\n\nSigning/verification relies on distribution of public keys _prior_ to API communication. Public keys are commonly refreshed/delivered to clients once every 30 days (stored in the browser's IndexedDB or localStorage).\n\n## Reversible Encryption/Decryption\n\nThe encrypt/decrypt methods provide a way to encrypt text using a shared encryption key.\n\n```javascript\nconst sharedKey = 'secret code'\nconst source = 'crypto makes things hard to read'\nconst encrypted = await crypto.encrypt(source, sharedKey)\nconst decrypted = await crypto.decrypt(encrypted, sharedKey)\n```\n\nAnyone who obtains the encryption key can decrypt data.\n\nThis library produces content that contains a salt, iv, and cipher content `${salt}${iv}${cipher}`. In older Node.js versions which do not support webcrypto, the cipher content is `${salt}${iv}${authTag}${cipher}` where `authTag` is a 16-bit string produced and consumed by encrypt/decypt.\n\nThis library will automatically decrypt tokens in the aforementioned format, assuming the appropriate encryption key is provided. Other libraries can decrypt tokens by parsing the `salt `, `iv `, and `cipher` (and `authTag` when appropriate), then performing decryption using these parts and the shared encryption key.\n\n## Public Key Encryption/Private Key Decryption\n\nIt is possible to encrypt content with a public key and decrypt it with the corresponding private key. This produces/uses RSA-OAEP keys (SHA-256).\n\n```javascript\nconst { publicKey, privateKey } = await crypto.generateRSAKeyPair()\nconst source = 'crypto makes things hard to read'\nconst encrypted = await crypto.encrypt(source, publicKey)\nconst decrypted = await crypto.decrypt(encrypted, privateKey)\n```\n\nTypically this is used to encrypt communications. The client receives the private key while the server stores the public key. The server encrypts data with the public key before sending it to the client. The client decrypts data using the private key.\n\n## Encrypt/Decrypt JSON\n\nObjects are converted to/from strings automatically. Encryption only works on string values, so conversion is always done automatically whenever an attempt to encrypt an object is detected. Decryption will automatically attempt to parse string content into an object. If parsing fails, the decrypted string is returned. To prevent the decrypt method from auto-parsing a string into an object, pass `false` as the third argument to the `decrypt()` method (as illustrated in the very last line of the following example).\n\n```javascript\nconst obj = { example: true }\nconst encObj = await crypto.encrypt(obj, encryptionKey)\nconst decObj = await crypto.decrypt(encObj, encryptionKey)\n\n// Using public/private keys (RSA-OAEP)\nconst obj = { example: true }\nconst { publicKey, privateKey } = await crypto.generateRSAKeyPair()\nconst encObj = await crypto.encrypt(obj, publicKey)\nconst decObj = await crypto.decrypt(encObj, privateKey[, false])\n```\n\nThese methods are lightweight wrappers around `encrypt()` and `decrypt()`.\n\n## One Time Passwords (HOTP, TOTP)\n\nThis library can generate HMAC-based OTPs and time-based OTPs. TOTPs are compatible with tools like Google Authenticator (see note).\n\n### HMAC-Based One Time Password (HOTP)\n\n**Syntax:**\n\n`HOTP(secret[, options])`\n\n**Options:** _(defaults are shown)_\n\n```javascript\n{\n  counter: 0,\n  algorithm: 'SHA-1', // Other options: SHA-256, SHA-384, SHA-512\n  digits: 6, // Can also be 8\n}\n```\n\n**Example:**\n\n```javascript\nconst secret = 'password' // 8 character secret (or 16, 24, 32, etc - must be evenly divisible by 8)\nconst hotp = crypto.HOTP(secret)\nconsole.log(hotp) // 328482\n```\n\n### Time-Based One Time Password (TOTP)\n\n**Syntax:**\n\n`TOTP(secret[, options])`\n\n**Options:** _(defaults are shown)_\n\n```javascript\n{\n  algorithm: 'SHA-1', // Other options: SHA-256, SHA-384, SHA-512\n  digits: 6, // Can also be 8\n  seconds: 30,\n  timestamp: null // Date.getTime() - used to retrieve old values (instead of seconds)\n}\n```\n\n**Example:**\n\n```javascript\nconst secret = 'password' // 8 character secret (or 16, 24, 32, etc - must be evenly divisible by 8)\nconst totp = crypto.TOTP(secret)\nconsole.log(totp) // 6 digit code changes every 30 seconds\n```\n\n#### Google Authenticator\n\nGoogle Authenticator uses Base32-encoded 16 character secrets.\n\nTo generate a key for Google Authenticator, use this library's base32 encoding:\n\n```javascript\nconst key = crypto.base32.encode('passwordpassword') // Output: OBQXG43XN5ZGI4DBONZXO33SMQ======\n```\n\nTo produce a UTF-8 string from a base32 string, use this library's base32 decoding:\n\n```javascript\nconst text = crypt.base32.decode('OBQXG43XN5ZGI4DBONZXO33SMQ======') // Output: passwordpassword\n```\n\n## Signed JSON Web Tokens (JWT)\n\nEasily generate and verify signed JWTs using HMAC (HS), RSA-PKCS1-v1_5 (RS), RSA-PSS (PS), and ECDSA (EC) 256-bit, 384-bit, or 512-bit algorithms.\n\nThe default algorithm is `EC256`. This produces smaller output, but is slightly slower than `RS256` (which is slightly larger).\n\n```javascript\nconst secret = 'secret'\nconst token = await crypto.JWT.create({\n  secret,\n  algorithm: 'HS256',\n  issuer: 'acme corp',\n  account: 'acct name',\n  claims: {\n    name: 'John Doe',\n    admin: true\n  },\n  headers: { kid: 'testdata' }\n})\n\nconst verified = await crypto.JWT.verify(token, secret)\n```\n\nThe issuer (iss), account (sub), claims, and headers are all optional.\n\nThe example above uses a shared key for signing and verifying JWTs. A more secure option is to use public/private keypairs.\n\nThere are two ways to use public/private keypairs.\n\n### Custom PKI Keypair\n\nA custom signing key (in PEM format) can be provided as the secret.\n\n```javascript\nconst { publicKey, privateKey } = crypto.generateRSAKeyPair(2048, 'SHA-256')\nconst secret = crypto.PEM.encodePrivateKey(privateKey)\nconst token = await crypto.JWT.create({\n  secret,\n  algorithm: 'HS256',\n  issuer: 'acme corp',\n  account: 'acct name',\n  claims: {\n    name: 'John Doe',\n    admin: true\n  },\n  headers: { kid: 'testdata' }\n})\n\nconst verified = await crypto.JWT.verify(token, crypto.PEM.encodePublicKey(publicKey))\n```\n\n#### Autogenerate PKI Keypair\n\nAlternatively, the keypair can be automatically generated.\n\n```javascript\n// Notice there is no \"secret\" attribute and the\n// result of the create method is an array containing\n// the token, public key (verificationKey), and private\n// key (signingKey).\nconst [token, verificationKeyPEM, signingKeyPEM] = await crypto.JWT.create({\n  algorithm: 'HS256',\n  issuer: 'acme corp',\n  account: 'acct name',\n  claims: {\n    name: 'John Doe',\n    admin: true\n  },\n  headers: { kid: 'testdata' }\n})\n\nconst verified = await crypto.JWT.verify(token, publicKey)\n```\n\nSee [here](https://jwt.io/introduction) for general JWT details.\n\n## Exported Functions\n\nThe following methods are importable from this module:\n\n```javascript\nimport {\n  encrypt,\n  decrypt,\n  encryptionAlgorithm,\n  generateKeys,\n  generateRSAKeyPair,\n  generateECDSAKeyPair,\n  generateECKeyPair,\n  sign,\n  verify,\n  HOTP,\n  TOTP,\n  base32,\n  PEM,\n  JWT\n} from '@ngnjs/libcrypto'\n```\n\nMost of these are defined in the examples above. The remainder are documented below:\n\n**encryptionAlgorithm(secret)**\n\nGiven a shared encryption key or public/private key (PEM), this method determines which encryption algorithm is used.\n\n**PEM**\n\nThis is an object/namespace containing several PEM-specific functions:\n\n1. `isKey(string)`_boolean_\n2. `isPrivateKey(string)`_boolean_\n3. `isPublicKey(string)`_boolean_\n4. `typeOf(string)`_string_ (`RSA` or `EC`)\n5. *`extractKey(string, algorithm)`_CryptoKey_\n6. *`encode(label, code, type)`_string_ (PEM)\n7. *`decode(key)`_ArrayBuffer_\n8. *`encodePrivateKey(key, type)`_string_ Encodes a private PEM\n9. *`encodePublicKey(key, type)`_string_ Encodes a public PEM\n10. *`getDefaultAlgorithm(pem, algorithm, type)`_string_ RSA/RSASSA-PKCS1-v1_5/P-256\n\nAll functions marked with `*` are designed primarily for internal use, but are exposed to provide granular control over PEM creation/consumption.\n\n---\n\n## Additional Docs\n\nThe code contains comments with syntax documentation for all methods.\n","funding_links":["https://github.com/sponsors/ngnjs","https://github.com/sponsors/coreybutler","https://github.com/sponsors/gbdrummer"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fngnjs%2Flibcrypto","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fngnjs%2Flibcrypto","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fngnjs%2Flibcrypto/lists"}