{"id":13339964,"url":"https://github.com/antonioconselheiro/encrypted-uri","last_synced_at":"2025-03-11T16:31:33.310Z","repository":{"id":213974797,"uuid":"735391070","full_name":"antonioconselheiro/encrypted-uri","owner":"antonioconselheiro","description":"encrypted uri","archived":false,"fork":false,"pushed_at":"2025-02-13T12:04:43.000Z","size":2518,"stargazers_count":3,"open_issues_count":7,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-13T13:25:42.401Z","etag":null,"topics":["encrypted","encrypted-data","encryption-algorithms","specification","uri","uri-solutions","uri-template"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/antonioconselheiro.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-12-24T18:43:06.000Z","updated_at":"2025-02-13T12:04:46.000Z","dependencies_parsed_at":"2023-12-28T00:06:48.330Z","dependency_job_id":"f9ae9b65-c716-48b9-90e4-51a51d51a137","html_url":"https://github.com/antonioconselheiro/encrypted-uri","commit_stats":null,"previous_names":["antonioconselheiro/encrypted-query-string"],"tags_count":21,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antonioconselheiro%2Fencrypted-uri","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antonioconselheiro%2Fencrypted-uri/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antonioconselheiro%2Fencrypted-uri/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antonioconselheiro%2Fencrypted-uri/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/antonioconselheiro","download_url":"https://codeload.github.com/antonioconselheiro/encrypted-uri/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243070292,"owners_count":20231421,"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":["encrypted","encrypted-data","encryption-algorithms","specification","uri","uri-solutions","uri-template"],"created_at":"2024-07-29T19:21:23.156Z","updated_at":"2025-03-11T16:31:32.462Z","avatar_url":"https://github.com/antonioconselheiro.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003e \"He that hath an ear, let him hear what the Spirit saith unto the churches; To him that overcometh will I give to eat of the hidden manna, and will give him a white stone, and in the stone a new name written, which no man knoweth saving he that receiveth it.\"\n\u003e Apocalypse 2:17\n\n# Encrypted URI\n## URI Encrypted Scheme Specification\n\n[![npm version](https://badge.fury.io/js/@encrypted-uri%2Fcore.svg)](https://github.com/antonioconselheiro/encrypted-uri)\n[![Npm Total Downloads](https://img.shields.io/npm/dt/@encrypted-uri/core.svg)](https://github.com/antonioconselheiro/encrypted-uri)\n[![Npm Monthly Downloads](https://img.shields.io/npm/dm/@encrypted-uri/core.svg)](https://github.com/antonioconselheiro/encrypted-uri)\n\nEncode to identify different types of encrypted content into a URI allowing the user to customize his ciphers with his preferred encryption algorithm.\n\n## Run example\n[Open example app](https://antonioconselheiro.github.io/encrypted-uri/ciphers-example/browser/)\n\n## Installation\n\n```npm install @encrypted-uri/core --save```\n\nThe core will provide you with the main tools to interpret an Encrypted URI and to direct the content to the correct decryption algorithm, but the core does not include any algorithm, you will need to install this separately.\n\n```npm install @encrypted-uri/ciphers --save```\n\n## Purpose\n\nThe purpose of Encrypted URI is to be used to storage ciphered content in a qrcode. Through this encode it is possible to represent an encryption cipher with its main parameters in a lean way (to generate less dense qrcodes).\n\nEncryption keys, private document signing keys and wallet seeds are examples of extremely sensitive information, which leads to a demand not to store them digitally, but physically and encrypted.\n\nThis tool is mainly proposed for encryption algorithms that can be decrypted with a key, but other types of algorithms can be supported if needed.\n\nThe encode allows customize your app defaults params for encryptation, you can also allow your user customize the algorithm in which he will store the information in his custody.\n\n## Syntax\nEncrypted URI are composed of five parts:\n\n```encrypted:[algorithm][?[args]];[cipher]```\n\nThe ```encrypted``` keyword identifies the string as encrypted uri.\n\nThe ```algorithm``` is the algorithm name, if not set, ```aes/cbc``` MUST be  assumed. The ```mode``` is separatted from algorithm name by a bar, like ```aes/cbc```. If the algorithm is set just as ```aes```, the operation mode MUST be  assumed as CBC.\n\nThe ```args``` are query string format arguments with values encoded into percent-encoded. If the algorithm requires one single mandatory argument, when this argument is send alone in ```args``` it's not needed to include the attribute name.\n\nThe ```cipher``` is the cipher or cipher params in a [OpenSSL compatible string](https://www.openssl.org/docs/man1.0.2/man1/openssl-enc.html), the salt param are sent in the header Salted_ in the bytes.\n\n## Example\nThe default, with default values ignored:\n```encrypted:?249c3d09119;U2FsdGVkX1mxOv5WpmRGHXZouip==```\n\nWith all parameters include:\n```encrypted:aes/cbc?iv=249c3d09119\u0026pad=pkcs%237;U2FsdGVkX1mxOv5WpmRGHXZouip```\n\nCustomized:\n```encrypted:aes?iv=249c3d09119;U2FsdGVkX1mxOv5WpmRGHXZouip```\n\nAlgorithm with no param:\n```encrypted:aes/ecb;U2FsdGVkX1mxOv5WpmRGHXZouip```\n\n## How to use\nBasic use, how to decode and encrypt and how to decode and decrypt: \n\n```typescript\nimport { EncryptedURIAlgorithm, EncryptedURIDecrypter, EncryptedURIEncrypter, TEncryptedURI, TEncryptedURIResultset, TURIParams } from '@encrypted-uri/core';\nimport { ecb } from '@noble/ciphers/aes';\nimport { bytesToUtf8, utf8ToBytes } from '@noble/ciphers/utils';\nimport { randomBytes } from '@noble/hashes/utils';\nimport { base64 } from '@scure/base';\n\nclass EncryptedURIAESECBDecrypter\u003cT extends TURIParams = TURIParams\u003e extends EncryptedURIDecrypter\u003cT\u003e {\n  constructor(\n    decoded: TEncryptedURI\u003cT\u003e,\n    password: string\n  ) {\n    super(decoded, password);\n  }\n\n  async decrypt(): Promise\u003cstring\u003e {\n    const cipher = base64.decode(this.decoded.cipher || '');\n    const params = getSalt(cipher, this.decoded?.params);\n    const result = await ecb(kdf(this.password, params.salt, this.decoded))\n      .decrypt(params.cipher);\n\n    return bytesToUtf8(result);\n  }\n}\n\n@EncryptedURIAlgorithm({\n  algorithm: 'aes/ecb',\n  decrypter: EncryptedURIAESECBDecrypter\n})\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nclass EncryptedURIAESECBEncrypter\u003cT extends TURIParams = TURIParams\u003e extends EncryptedURIEncrypter\u003cTURIParams\u003e {\n\n  constructor(\n    params: TEncryptedURIResultset\u003cT\u003e\n  ) {\n    super(params);\n  }\n\n  async encrypt(): Promise\u003cTEncryptedURI\u003cT\u003e\u003e {\n    const content = utf8ToBytes(this.params.content);\n    const saltLength = 8;\n    const salt = randomBytes(saltLength);\n    const rawCipher = await ecb(kdf(this.params.password, salt, this.params)).encrypt(content);\n    const cipher = base64.encode(OpenSSLSerializer.encode(rawCipher, salt));\n\n    return Promise.resolve({ cipher });\n  }\n}\n\n\n```\n\nAdvanced use, how to add default encrypter and how to add more alias to an algorithm: \n```typescript\nimport { EncryptedURI, EncryptedURIAlgorithm, EncryptedURIDecrypter, EncryptedURIEncrypter, TEncryptedURI, TEncryptedURIResultset } from '@encrypted-uri/core';\nimport { bytesToUtf8, hexToBytes, utf8ToBytes } from '@noble/ciphers/utils';\nimport { cbc } from '@noble/ciphers/webcrypto/aes';\nimport { randomBytes } from '@noble/hashes/utils';\nimport { base64 } from '@scure/base';\n\nclass EncryptedURIAESCBCDecrypter extends EncryptedURIDecrypter\u003cTInitializationVectorParams\u003e {\n  constructor(\n    decoded: TEncryptedURI\u003cTInitializationVectorParams\u003e,\n    password: string\n  ) {\n    super(decoded, password);\n  }\n\n  async decrypt(): Promise\u003cstring\u003e {\n    const ivhex = getInitializationVector(this.decoded);\n    const cipher = base64.decode(this.decoded.cipher);\n    const params = getSalt(cipher, this.decoded?.params);\n\n    const result = await cbc(kdf(this.password, params.salt, this.decoded), hexToBytes(ivhex))\n      .decrypt(params.cipher);\n\n    return bytesToUtf8(result);\n  }\n}\n\n@EncryptedURIAlgorithm({\n  algorithm: 'aes/cbc',\n  decrypter: EncryptedURIAESCBCDecrypter\n})\nclass EncryptedURIAESCBCEncrypter extends EncryptedURIEncrypter\u003cTInitializationVectorParams\u003e {\n\n  constructor(\n    params: TEncryptedURIResultset\u003cTInitializationVectorParams\u003e\n  ) {\n    super(params);\n  }\n\n  async encrypt(): Promise\u003cTEncryptedURI\u003cTInitializationVectorParams\u003e\u003e {\n    const ivhex = getInitializationVector(this.params);\n    const iv = hexToBytes(ivhex);\n    const content = utf8ToBytes(this.params.content);\n    const saltLength = 8;\n    const salt = randomBytes(saltLength);\n    const cipher = await cbc(kdf(this.params.password, salt, this.params), iv).encrypt(content);\n\n    return Promise.resolve({\n      cipher: base64.encode(OpenSSLSerializer.encode(cipher, salt)),\n      params: { iv: ivhex }\n    });\n  }\n}\n\nEncryptedURI.setAlgorithm('', EncryptedURIAESCBCEncrypter, EncryptedURIAESCBCDecrypter);\nEncryptedURI.setAlgorithm('aes', EncryptedURIAESCBCEncrypter, EncryptedURIAESCBCDecrypter);\n\n```\n\n## Example of practical application\n - [Private QRcode](https://antonioconselheiro.github.io/private-qrcode/#/home), allow you to create private qrcode using encrypted URI with AES algorithm fixed in it. It allow you to save your seeds, nsec and keys physically printed.\n\n## Contribute\n[CONTRIBUTE.md](./CONTRIBUTE.md)\n\n## Donate\nHelp me continue working on tools for the bitcoin and nostr universe, like this one. #zapthedev\n\nThere's still a lot of work to do.\n\nLighting donate: \u003ca href=\"lightning:antonioconselheiro@getalby.com\"\u003elightning:antonioconselheiro@getalby.com\u003c/a\u003e\n\n![zap me](https://raw.githubusercontent.com/antonioconselheiro/antonioconselheiro/main/img/qrcode-wallet-lighting.png)\n\nBitcoin onchain donate: \u003ca href=\"bitcoin:bc1qrm99lmmpwk7zsh7njpgthw87yvdm38j2lzpq7q\"\u003ebc1qrm99lmmpwk7zsh7njpgthw87yvdm38j2lzpq7q\u003c/a\u003e\n\n![zap me](https://raw.githubusercontent.com/antonioconselheiro/antonioconselheiro/main/img/qrcode-wallet-bitcoin.png)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fantonioconselheiro%2Fencrypted-uri","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fantonioconselheiro%2Fencrypted-uri","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fantonioconselheiro%2Fencrypted-uri/lists"}