feat: add sncryptio-node package

This commit is contained in:
Karol Sójko 2022-07-06 12:13:38 +02:00
parent 033eeda50a
commit 60e8974580
No known key found for this signature in database
GPG key ID: A50543BF560BDEB0
21 changed files with 599 additions and 19 deletions

87
.pnp.cjs generated
View file

@ -64,6 +64,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"name": "@standardnotes/settings",\
"reference": "workspace:packages/settings"\
},\
{\
"name": "@standardnotes/sncrypto-node",\
"reference": "workspace:packages/sncrypto-node"\
},\
{\
"name": "@standardnotes/syncing-server",\
"reference": "workspace:packages/syncing-server"\
@ -88,6 +92,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["@standardnotes/security", ["workspace:packages/security"]],\
["@standardnotes/server-monorepo", ["workspace:."]],\
["@standardnotes/settings", ["workspace:packages/settings"]],\
["@standardnotes/sncrypto-node", ["workspace:packages/sncrypto-node"]],\
["@standardnotes/syncing-server", ["workspace:packages/syncing-server"]],\
["@standardnotes/time", ["workspace:packages/time"]]\
],\
@ -2759,7 +2764,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["@standardnotes/security", "workspace:packages/security"],\
["@standardnotes/settings", "workspace:packages/settings"],\
["@standardnotes/sncrypto-common", "npm:1.9.0"],\
["@standardnotes/sncrypto-node", "npm:1.8.3"],\
["@standardnotes/sncrypto-node", "workspace:packages/sncrypto-node"],\
["@standardnotes/time", "workspace:packages/time"],\
["@types/bcryptjs", "npm:2.4.2"],\
["@types/cors", "npm:2.8.12"],\
@ -2914,7 +2919,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["@standardnotes/domain-events-infra", "workspace:packages/domain-events-infra"],\
["@standardnotes/security", "workspace:packages/security"],\
["@standardnotes/sncrypto-common", "npm:1.9.0"],\
["@standardnotes/sncrypto-node", "npm:1.8.3"],\
["@standardnotes/sncrypto-node", "workspace:packages/sncrypto-node"],\
["@standardnotes/time", "workspace:packages/time"],\
["@types/connect-busboy", "npm:1.0.0"],\
["@types/cors", "npm:2.8.12"],\
@ -3126,13 +3131,22 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
}]\
]],\
["@standardnotes/sncrypto-node", [\
["npm:1.8.3", {\
"packageLocation": "./.yarn/cache/@standardnotes-sncrypto-node-npm-1.8.3-5d28cdd37d-b3c866bfba.zip/node_modules/@standardnotes/sncrypto-node/",\
["workspace:packages/sncrypto-node", {\
"packageLocation": "./packages/sncrypto-node/",\
"packageDependencies": [\
["@standardnotes/sncrypto-node", "npm:1.8.3"],\
["@standardnotes/sncrypto-common", "npm:1.9.0"]\
["@standardnotes/sncrypto-node", "workspace:packages/sncrypto-node"],\
["@standardnotes/sncrypto-common", "npm:1.9.0"],\
["@types/jest", "npm:28.1.4"],\
["@types/node", "npm:18.0.3"],\
["@typescript-eslint/eslint-plugin", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:5.30.5"],\
["eslint-plugin-prettier", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:4.2.1"],\
["jest", "virtual:e1128e9ebb31076ea8e955c00397fd108ee8bf0fb2df3b2a603c510b7014a507cfa360bccf848efc1ec8c431656aa94c5ad08bcec32950bdf1278d01cd890e4f#npm:28.1.2"],\
["reflect-metadata", "npm:0.1.13"],\
["regenerator-runtime", "npm:0.13.9"],\
["ts-jest", "virtual:e1128e9ebb31076ea8e955c00397fd108ee8bf0fb2df3b2a603c510b7014a507cfa360bccf848efc1ec8c431656aa94c5ad08bcec32950bdf1278d01cd890e4f#npm:28.0.5"],\
["ts-loader", "virtual:251b55e6186f136d0456117ba65ba163d1a38b49e5d09875aa42c66c71e5a9085f9a3cc24c7aae5da7499c53d95e6948b9284db4d7d1f035f288826df740c6bf#npm:9.3.1"]\
],\
"linkType": "HARD"\
"linkType": "SOFT"\
}]\
]],\
["@standardnotes/syncing-server", [\
@ -6337,6 +6351,17 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"linkType": "HARD"\
}]\
]],\
["enhanced-resolve", [\
["npm:5.10.0", {\
"packageLocation": "./.yarn/cache/enhanced-resolve-npm-5.10.0-7941304306-0bb9830704.zip/node_modules/enhanced-resolve/",\
"packageDependencies": [\
["enhanced-resolve", "npm:5.10.0"],\
["graceful-fs", "npm:4.2.10"],\
["tapable", "npm:2.2.1"]\
],\
"linkType": "HARD"\
}]\
]],\
["env-paths", [\
["npm:2.2.1", {\
"packageLocation": "./.yarn/cache/env-paths-npm-2.2.1-7c7577428c-65b5df55a8.zip/node_modules/env-paths/",\
@ -12178,6 +12203,15 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"linkType": "HARD"\
}]\
]],\
["regenerator-runtime", [\
["npm:0.13.9", {\
"packageLocation": "./.yarn/cache/regenerator-runtime-npm-0.13.9-6d02340eec-65ed455fe5.zip/node_modules/regenerator-runtime/",\
"packageDependencies": [\
["regenerator-runtime", "npm:0.13.9"]\
],\
"linkType": "HARD"\
}]\
]],\
["regexpp", [\
["npm:3.2.0", {\
"packageLocation": "./.yarn/cache/regexpp-npm-3.2.0-2513f32cfc-a78dc5c715.zip/node_modules/regexpp/",\
@ -13124,6 +13158,15 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"linkType": "HARD"\
}]\
]],\
["tapable", [\
["npm:2.2.1", {\
"packageLocation": "./.yarn/cache/tapable-npm-2.2.1-8cf5ff3039-3b7a1b4d86.zip/node_modules/tapable/",\
"packageDependencies": [\
["tapable", "npm:2.2.1"]\
],\
"linkType": "HARD"\
}]\
]],\
["tar", [\
["npm:6.1.11", {\
"packageLocation": "./.yarn/cache/tar-npm-6.1.11-e6ac3cba9c-a04c07bb9e.zip/node_modules/tar/",\
@ -13491,6 +13534,36 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"linkType": "HARD"\
}]\
]],\
["ts-loader", [\
["npm:9.3.1", {\
"packageLocation": "./.yarn/cache/ts-loader-npm-9.3.1-634433ef6a-462a8ac315.zip/node_modules/ts-loader/",\
"packageDependencies": [\
["ts-loader", "npm:9.3.1"]\
],\
"linkType": "SOFT"\
}],\
["virtual:251b55e6186f136d0456117ba65ba163d1a38b49e5d09875aa42c66c71e5a9085f9a3cc24c7aae5da7499c53d95e6948b9284db4d7d1f035f288826df740c6bf#npm:9.3.1", {\
"packageLocation": "./.yarn/__virtual__/ts-loader-virtual-2eeaee133b/0/cache/ts-loader-npm-9.3.1-634433ef6a-462a8ac315.zip/node_modules/ts-loader/",\
"packageDependencies": [\
["ts-loader", "virtual:251b55e6186f136d0456117ba65ba163d1a38b49e5d09875aa42c66c71e5a9085f9a3cc24c7aae5da7499c53d95e6948b9284db4d7d1f035f288826df740c6bf#npm:9.3.1"],\
["@types/typescript", null],\
["@types/webpack", null],\
["chalk", "npm:4.1.2"],\
["enhanced-resolve", "npm:5.10.0"],\
["micromatch", "npm:4.0.5"],\
["semver", "npm:7.3.7"],\
["typescript", null],\
["webpack", null]\
],\
"packagePeers": [\
"@types/typescript",\
"@types/webpack",\
"typescript",\
"webpack"\
],\
"linkType": "HARD"\
}]\
]],\
["ts-node", [\
["npm:10.8.2", {\
"packageLocation": "./.yarn/cache/ts-node-npm-10.8.2-f3c0c9eaee-1eede939be.zip/node_modules/ts-node/",\

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -44,7 +44,7 @@
"@standardnotes/security": "workspace:*",
"@standardnotes/settings": "workspace:*",
"@standardnotes/sncrypto-common": "^1.9.0",
"@standardnotes/sncrypto-node": "^1.8.3",
"@standardnotes/sncrypto-node": "workspace:*",
"@standardnotes/time": "workspace:*",
"aws-sdk": "^2.1159.0",
"axios": "0.24.0",

View file

@ -32,7 +32,7 @@
"@standardnotes/domain-events-infra": "workspace:*",
"@standardnotes/security": "workspace:*",
"@standardnotes/sncrypto-common": "^1.9.0",
"@standardnotes/sncrypto-node": "^1.8.3",
"@standardnotes/sncrypto-node": "workspace:*",
"@standardnotes/time": "workspace:*",
"aws-sdk": "^2.1158.0",
"connect-busboy": "^1.0.0",

View file

@ -0,0 +1,4 @@
dist
test
*.config.js
test-server.js

View file

@ -0,0 +1,6 @@
{
"extends": "../../.eslintrc",
"parserOptions": {
"project": "./linter.tsconfig.json"
}
}

View file

@ -0,0 +1,83 @@
# Change Log
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.8.4](https://github.com/standardnotes/snjs/compare/@standardnotes/sncrypto-node@1.8.3...@standardnotes/sncrypto-node@1.8.4) (2022-07-04)
### Bug Fixes
* add missing reflect-metadata package to all packages ([ce3a5bb](https://github.com/standardnotes/snjs/commit/ce3a5bbf3f1d2276ac4abc3eec3c6a44c8c3ba9b))
* unit tests running ([9ddc55c](https://github.com/standardnotes/snjs/commit/9ddc55c59c781e2bcc366304a6d0cc88d0e0865d))
## [1.8.3](https://github.com/standardnotes/snjs/compare/@standardnotes/sncrypto-node@1.8.2...@standardnotes/sncrypto-node@1.8.3) (2022-05-20)
**Note:** Version bump only for package @standardnotes/sncrypto-node
## [1.8.2](https://github.com/standardnotes/snjs/compare/@standardnotes/sncrypto-node@1.8.0...@standardnotes/sncrypto-node@1.8.2) (2022-05-04)
### Bug Fixes
* config package missing dependencies ([3dec12f](https://github.com/standardnotes/snjs/commit/3dec12fa4a83a8aed8419819eafb7c34795cb09f))
## [1.8.1](https://github.com/standardnotes/snjs/compare/@standardnotes/sncrypto-node@1.8.0...@standardnotes/sncrypto-node@1.8.1) (2022-05-04)
### Bug Fixes
* config package missing dependencies ([3dec12f](https://github.com/standardnotes/snjs/commit/3dec12fa4a83a8aed8419819eafb7c34795cb09f))
# [1.8.0](https://github.com/standardnotes/snjs/compare/@standardnotes/sncrypto-node@1.7.0...@standardnotes/sncrypto-node@1.8.0) (2022-05-03)
### Features
* rename SNCryptoNode to CryptoNode and fix sha256 function ([2c0cd81](https://github.com/standardnotes/snjs/commit/2c0cd81f952edfbe1f770534a269ddcaf9fa6678))
# [1.7.0](https://github.com/standardnotes/snjs/compare/@standardnotes/sncrypto-node@1.6.8...@standardnotes/sncrypto-node@1.7.0) (2022-04-28)
### Features
* refactor sncrypto to add unified sha256 and base64 usage ([#715](https://github.com/standardnotes/snjs/issues/715)) ([93aef4d](https://github.com/standardnotes/snjs/commit/93aef4d39228a63f01aa90a88e5d28c3375ed707))
## [1.6.8](https://github.com/standardnotes/snjs/compare/@standardnotes/sncrypto-node@1.6.7...@standardnotes/sncrypto-node@1.6.8) (2022-04-22)
**Note:** Version bump only for package @standardnotes/sncrypto-node
## [1.6.7](https://github.com/standardnotes/snjs/compare/@standardnotes/sncrypto-node@1.6.6...@standardnotes/sncrypto-node@1.6.7) (2022-04-15)
**Note:** Version bump only for package @standardnotes/sncrypto-node
## [1.6.6](https://github.com/standardnotes/snjs/compare/@standardnotes/sncrypto-node@1.6.5...@standardnotes/sncrypto-node@1.6.6) (2022-04-11)
**Note:** Version bump only for package @standardnotes/sncrypto-node
## [1.6.5](https://github.com/standardnotes/snjs/compare/@standardnotes/sncrypto-node@1.6.4...@standardnotes/sncrypto-node@1.6.5) (2022-03-31)
**Note:** Version bump only for package @standardnotes/sncrypto-node
## [1.6.4](https://github.com/standardnotes/snjs/compare/@standardnotes/sncrypto-node@1.6.2...@standardnotes/sncrypto-node@1.6.4) (2022-02-28)
### Bug Fixes
* add pseudo change to get lerna to trigger ([41e6817](https://github.com/standardnotes/snjs/commit/41e6817bbf726b0932cdf16f58622328b9e42803))
* add pseudo change to get lerna to trigger ([74e8af6](https://github.com/standardnotes/snjs/commit/74e8af640e3d0b8c2f0fc7cf792f4e2cdf33b50c))
## [1.6.3](https://github.com/standardnotes/snjs/compare/@standardnotes/sncrypto-node@1.6.2...@standardnotes/sncrypto-node@1.6.3) (2022-02-28)
### Bug Fixes
* add pseudo change to get lerna to trigger ([41e6817](https://github.com/standardnotes/snjs/commit/41e6817bbf726b0932cdf16f58622328b9e42803))
* add pseudo change to get lerna to trigger ([74e8af6](https://github.com/standardnotes/snjs/commit/74e8af640e3d0b8c2f0fc7cf792f4e2cdf33b50c))
## [1.6.2](https://github.com/standardnotes/snjs/compare/@standardnotes/sncrypto-node@1.6.1...@standardnotes/sncrypto-node@1.6.2) (2022-02-24)
**Note:** Version bump only for package @standardnotes/sncrypto-node
## [1.6.1](https://github.com/standardnotes/snjs/compare/@standardnotes/sncrypto-node@1.6.0...@standardnotes/sncrypto-node@1.6.1) (2022-02-16)
**Note:** Version bump only for package @standardnotes/sncrypto-node
# 1.6.0 (2022-01-14)
### Features
* move sncrypto packages to snjs monorepo ([#554](https://github.com/standardnotes/snjs/issues/554)) ([db83991](https://github.com/standardnotes/snjs/commit/db8399190d9d10fdc31060568b836c62933fd525))

View file

@ -0,0 +1,21 @@
# SNCrypto for Node.js
[![lerna](https://img.shields.io/badge/maintained%20with-lerna-cc00ff.svg)](https://lerna.js.org/)
Cryptographic primitives as a Node.js library -- used by server-side Standard Notes services, e.g. [Files](https://github.com/standardnotes/files).
## Installing
```
yarn add @standardnotes/sncrypto-node
```
## Supported Algorithms
- AES-GCM
## Tests
```
yarn test
```

View file

@ -0,0 +1,11 @@
// eslint-disable-next-line @typescript-eslint/no-var-requires
const base = require('../../jest.config');
module.exports = {
...base,
globals: {
'ts-jest': {
tsconfig: 'tsconfig.json',
},
}
};

View file

@ -0,0 +1,4 @@
{
"extends": "./tsconfig.json",
"exclude": ["dist"]
}

View file

@ -0,0 +1,40 @@
{
"name": "@standardnotes/sncrypto-node",
"version": "1.9.0",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
"description": "SNCrypto for Node.js",
"main": "dist/src/index.js",
"types": "dist/src/index.d.ts",
"files": [
"dist/**/*.js",
"dist/**/*.js.map",
"dist/**/*.d.ts"
],
"license": "AGPL-3.0-or-later",
"publishConfig": {
"access": "public"
},
"scripts": {
"clean": "rm -fr dist",
"prebuild": "yarn clean",
"build": "tsc -p tsconfig.json",
"lint": "eslint . --ext .ts",
"test:unit": "jest spec"
},
"dependencies": {
"@standardnotes/sncrypto-common": "^1.9.0",
"reflect-metadata": "^0.1.13"
},
"devDependencies": {
"@types/jest": "^28.1.3",
"@types/node": "^18.0.0",
"@typescript-eslint/eslint-plugin": "^5.30.0",
"eslint-plugin-prettier": "^4.2.1",
"jest": "^28.1.2",
"regenerator-runtime": "^0.13.9",
"ts-jest": "^28.0.5",
"ts-loader": "^9.2.6"
}
}

View file

@ -0,0 +1,176 @@
import { CryptoNode } from './CryptoNode'
describe('CryptoNode', function () {
const crypto = new CryptoNode()
it('aes gcm', async function () {
const iv = await crypto.generateRandomKey(128)
const key = await crypto.generateRandomKey(256)
const unencrypted = 'hello world 🌍'
const encrypted = await crypto.aes256GcmEncrypt({ unencrypted, iv, key })
const decrypted = await crypto.aes256GcmDecrypt(encrypted, key)
expect(decrypted).toEqual(unencrypted)
})
// from https://github.com/xorbit/node-aes-gcm/blob/588f9066a217335acc56ab45559d2b46edc9fa83/test/test.js#L342
it('aes gcm NIST Test Case 15', async () => {
const key = 'feffe9928665731c6d6a8f9467308308' + 'feffe9928665731c6d6a8f9467308308'
const iv = 'cafebabefacedbaddecaf888'
const string =
'd9313225f88406e5a55909c5aff5269a' +
'86a7a9531534f7da2e4c303d8a318a72' +
'1c3c0c95956809532fcf0e2449a6b525' +
'b16aedf5aa0de657ba637b391aafd255'
const aad = ''
const desiredCiphertext = Buffer.from(
'522dc1f099567d07f47f37a32a84427d' +
'643a8cdcbfe5c0c97598a2bd2555d1aa' +
'8cb08e48590dbb3da7b08b1056828838' +
'c5f61e6393ba7a0abcc9f662898015ad',
'hex',
).toString('base64')
const desiredTag = 'b094dac5d93471bdec1a502270e3cc6c'
const encrypted = await crypto.aes256GcmEncrypt({
unencrypted: { string, encoding: 'hex' },
iv,
key,
aad,
})
expect(encrypted.ciphertext).toEqual(desiredCiphertext)
expect(encrypted.tag).toEqual(desiredTag)
expect(encrypted.iv).toEqual(iv)
const decrypted = await crypto.aes256GcmDecrypt(encrypted, key)
expect(decrypted).toEqual(string)
})
// from https://github.com/standardnotes/auth/blob/d5585b3ad0a27f58fb413ff2d85699d82b2e9b65/src/Domain/Encryption/Crypter.spec.ts#L32
it('should encrypt and decrypt data with an expected output', async () => {
const keys = [
'00000000000000000000000000000000' + '00000000000000000000000000000000',
'00000000000000000000000000000000' + '00000000000000000000000000000000',
'feffe9928665731c6d6a8f9467308308' + 'feffe9928665731c6d6a8f9467308308',
'feffe9928665731c6d6a8f9467308308' + 'feffe9928665731c6d6a8f9467308308',
'feffe9928665731c6d6a8f9467308308' + 'feffe9928665731c6d6a8f9467308308',
'feffe9928665731c6d6a8f9467308308' + 'feffe9928665731c6d6a8f9467308308',
]
const ivs = [
'000000000000000000000000',
'000000000000000000000000',
'cafebabefacedbaddecaf888',
'cafebabefacedbaddecaf888',
'cafebabefacedbad',
'9313225df88406e555909c5aff5269aa' +
'6a7a9538534f7da1e4c303d2a318a728' +
'c3c0c95156809539fcf0e2429a6b5254' +
'16aedbf5a0de6a57a637b39b',
]
const inputs = [
'',
'00000000000000000000000000000000',
'd9313225f88406e5a55909c5aff5269a' +
'86a7a9531534f7da2e4c303d8a318a72' +
'1c3c0c95956809532fcf0e2449a6b525' +
'b16aedf5aa0de657ba637b391aafd255',
'd9313225f88406e5a55909c5aff5269a' +
'86a7a9531534f7da2e4c303d8a318a72' +
'1c3c0c95956809532fcf0e2449a6b525' +
'b16aedf5aa0de657ba637b39',
'd9313225f88406e5a55909c5aff5269a' +
'86a7a9531534f7da2e4c303d8a318a72' +
'1c3c0c95956809532fcf0e2449a6b525' +
'b16aedf5aa0de657ba637b39',
'd9313225f88406e5a55909c5aff5269a' +
'86a7a9531534f7da2e4c303d8a318a72' +
'1c3c0c95956809532fcf0e2449a6b525' +
'b16aedf5aa0de657ba637b39',
]
const outputs = [
'',
'cea7403d4d606b6e074ec5d3baf39d18',
'522dc1f099567d07f47f37a32a84427d' +
'643a8cdcbfe5c0c97598a2bd2555d1aa' +
'8cb08e48590dbb3da7b08b1056828838' +
'c5f61e6393ba7a0abcc9f662898015ad',
'522dc1f099567d07f47f37a32a84427d' +
'643a8cdcbfe5c0c97598a2bd2555d1aa' +
'8cb08e48590dbb3da7b08b1056828838' +
'c5f61e6393ba7a0abcc9f662',
'c3762df1ca787d32ae47c13bf19844cb' +
'af1ae14d0b976afac52ff7d79bba9de0' +
'feb582d33934a4f0954cc2363bc73f78' +
'62ac430e64abe499f47c9b1f',
'5a8def2f0c9e53f1f75d7853659e2a20' +
'eeb2b22aafde6419a058ab4f6f746bf4' +
'0fc0c3b780f244452da3ebf1c5d82cde' +
'a2418997200ef82e44ae7e3f',
]
const aads = [
'',
'',
'',
'feedfacedeadbeeffeedfacedeadbeef' + 'abaddad2',
'feedfacedeadbeeffeedfacedeadbeef' + 'abaddad2',
'feedfacedeadbeeffeedfacedeadbeef' + 'abaddad2',
]
const tags = [
'530f8afbc74536b9a963b4f1c4cb738b',
'd0d1c8a799996bf0265b98b5d48ab919',
'b094dac5d93471bdec1a502270e3cc6c',
'76fc6ece0f4e1768cddf8853bb2d551b',
'3a337dbf46a792c45e454913fe2ea8f2',
'a44a8266ee1c8eb0c8b5d4cf5ae9f19a',
]
for (let i = 0; i < keys.length; i++) {
const string = inputs[i]
const aad = aads[i]
const iv = ivs[i]
const key = keys[i]
const desiredTag = tags[i]
const desiredCiphertext = Buffer.from(outputs[i], 'hex').toString('base64')
const encrypted = await crypto.aes256GcmEncrypt({
unencrypted: { string, encoding: 'hex' },
iv,
key,
aad,
})
expect(encrypted.ciphertext).toEqual(desiredCiphertext)
expect(encrypted.tag).toEqual(desiredTag)
expect(encrypted.iv).toEqual(iv)
const decrypted = await crypto.aes256GcmDecrypt(encrypted, key)
expect(decrypted).toEqual(string)
}
})
it('should encrypt data with SHA256', () => {
expect(crypto.sha256('eSyM3G8TkyzaCxDlQwXo0X7nkdrRkjEHN3TREmW7iQc4sKVibWj4pyQYZLacKAee')).toEqual(
'97e65d4c20152373cb0f787d73f480c6890076fec1753098768f60c93f8ef63a',
)
})
it('should base64 encode a utf8 string', () => {
expect(crypto.base64Encode('Hello World')).toEqual('SGVsbG8gV29ybGQ=')
})
it('should base64 encode a utf8 string with url safe option', () => {
expect(crypto.base64URLEncode('Hello World')).toEqual('SGVsbG8gV29ybGQ')
})
it('should base64 decode a utf8 string', () => {
expect(crypto.base64Decode('SGVsbG8gV29ybGQ=')).toEqual('Hello World')
})
})

View file

@ -0,0 +1,81 @@
import {
Aes256GcmEncrypted,
Aes256GcmInput,
HexString,
CryptoAes256GcmInterface,
CryptoSha256Interface,
CryptoBase64Interface,
Utf8String,
Base64String,
} from '@standardnotes/sncrypto-common'
import { createCipheriv, createDecipheriv, randomBytes, createHash } from 'crypto'
import { getBufferWithEncoding } from './Utils'
export class CryptoNode
implements CryptoAes256GcmInterface<BufferEncoding>, CryptoSha256Interface, CryptoBase64Interface
{
async aes256GcmEncrypt({
unencrypted,
iv,
key,
aad = '',
}: Aes256GcmInput<BufferEncoding>): Promise<Aes256GcmEncrypted<BufferEncoding>> {
const { buffer: dataBuffer, encoding } = getBufferWithEncoding(unencrypted)
const ivBuffer = Buffer.from(iv, 'hex')
const keyBuffer = Buffer.from(key, 'hex')
const cipher = createCipheriv('aes-256-gcm', keyBuffer, ivBuffer)
const aadBuffer = Buffer.from(aad, 'hex')
cipher.setAAD(aadBuffer)
const ciphertext = Buffer.concat([cipher.update(dataBuffer), cipher.final()]).toString('base64')
const tag = cipher.getAuthTag().toString('hex')
return { iv, tag, aad, ciphertext, encoding }
}
async aes256GcmDecrypt(encrypted: Aes256GcmEncrypted<BufferEncoding>, key: HexString): Promise<string> {
const { iv, tag, ciphertext, encoding, aad } = encrypted
const decipher = createDecipheriv('aes-256-gcm', Buffer.from(key, 'hex'), Buffer.from(iv, 'hex'))
decipher.setAuthTag(Buffer.from(tag, 'hex'))
decipher.setAAD(Buffer.from(aad, 'hex'))
const decrypted = Buffer.concat([decipher.update(Buffer.from(ciphertext, 'base64')), decipher.final()])
return decrypted.toString(encoding)
}
async generateRandomKey(bits: number): Promise<HexString> {
const bytes = bits / 8
const buf = randomBytes(bytes)
return buf.toString('hex')
}
sha256(text: Utf8String): HexString {
const hash = createHash('sha256').update(text)
return hash.digest('hex')
}
base64Encode(text: Utf8String): Base64String {
const { buffer } = getBufferWithEncoding({ string: text, encoding: 'utf8' })
return buffer.toString('base64')
}
base64URLEncode(text: Utf8String): Base64String {
const { buffer } = getBufferWithEncoding({ string: text, encoding: 'utf8' })
return buffer.toString('base64url')
}
base64Decode(base64String: Base64String): Utf8String {
const { buffer } = getBufferWithEncoding({ string: base64String, encoding: 'base64' })
return buffer.toString('utf8')
}
}

View file

@ -0,0 +1,20 @@
import { Unencrypted } from '@standardnotes/sncrypto-common'
/**
* Turns `unencrypted` into a `buffer` with `encoding`.
* @param unencrypted
*/
export function getBufferWithEncoding(unencrypted: Unencrypted<BufferEncoding>): {
buffer: Buffer
encoding: BufferEncoding
} {
if (typeof unencrypted === 'string') {
const encoding: BufferEncoding = 'utf-8'
const buffer = Buffer.from(unencrypted, encoding)
return { buffer, encoding }
}
const { string, encoding } = unencrypted
const buffer = Buffer.from(string, encoding)
return { buffer, encoding }
}

View file

@ -0,0 +1,2 @@
export * from './CryptoNode'
export * from './Utils'

View file

@ -0,0 +1,12 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"composite": true,
"outDir": "./dist",
"inlineSourceMap": true,
},
"include": [
"src/**/*"
],
"references": []
}

View file

@ -2027,7 +2027,7 @@ __metadata:
"@standardnotes/security": "workspace:*"
"@standardnotes/settings": "workspace:*"
"@standardnotes/sncrypto-common": ^1.9.0
"@standardnotes/sncrypto-node": ^1.8.3
"@standardnotes/sncrypto-node": "workspace:*"
"@standardnotes/time": "workspace:*"
"@types/bcryptjs": ^2.4.2
"@types/cors": ^2.8.9
@ -2181,7 +2181,7 @@ __metadata:
"@standardnotes/domain-events-infra": "workspace:*"
"@standardnotes/security": "workspace:*"
"@standardnotes/sncrypto-common": ^1.9.0
"@standardnotes/sncrypto-node": ^1.8.3
"@standardnotes/sncrypto-node": "workspace:*"
"@standardnotes/time": "workspace:*"
"@types/connect-busboy": ^1.0.0
"@types/cors": ^2.8.9
@ -2375,14 +2375,22 @@ __metadata:
languageName: node
linkType: hard
"@standardnotes/sncrypto-node@npm:^1.8.3":
version: 1.8.3
resolution: "@standardnotes/sncrypto-node@npm:1.8.3"
"@standardnotes/sncrypto-node@workspace:*, @standardnotes/sncrypto-node@workspace:packages/sncrypto-node":
version: 0.0.0-use.local
resolution: "@standardnotes/sncrypto-node@workspace:packages/sncrypto-node"
dependencies:
"@standardnotes/sncrypto-common": ^1.9.0
checksum: b3c866bfba63fbf673ce78de0a25b0abff5f2cf2476892f3fba76d55554d0d84e304d6f454dd9a482f723585e995fc56565f47a67ea52e53f6c3075f1c160286
languageName: node
linkType: hard
"@types/jest": ^28.1.3
"@types/node": ^18.0.0
"@typescript-eslint/eslint-plugin": ^5.30.0
eslint-plugin-prettier: ^4.2.1
jest: ^28.1.2
reflect-metadata: ^0.1.13
regenerator-runtime: ^0.13.9
ts-jest: ^28.0.5
ts-loader: ^9.2.6
languageName: unknown
linkType: soft
"@standardnotes/syncing-server@workspace:packages/syncing-server":
version: 0.0.0-use.local
@ -4935,6 +4943,16 @@ __metadata:
languageName: node
linkType: hard
"enhanced-resolve@npm:^5.0.0":
version: 5.10.0
resolution: "enhanced-resolve@npm:5.10.0"
dependencies:
graceful-fs: ^4.2.4
tapable: ^2.2.0
checksum: 0bb9830704db271610f900e8d79d70a740ea16f251263362b0c91af545576d09fe50103496606c1300a05e588372d6f9780a9bc2e30ce8ef9b827ec8f44687ff
languageName: node
linkType: hard
"env-paths@npm:^2.2.0":
version: 2.2.1
resolution: "env-paths@npm:2.2.1"
@ -5955,7 +5973,7 @@ __metadata:
languageName: node
linkType: hard
"graceful-fs@npm:^4.1.11, graceful-fs@npm:^4.1.15, graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.10, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9":
"graceful-fs@npm:^4.1.11, graceful-fs@npm:^4.1.15, graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.10, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9":
version: 4.2.10
resolution: "graceful-fs@npm:4.2.10"
checksum: 3f109d70ae123951905d85032ebeae3c2a5a7a997430df00ea30df0e3a6c60cf6689b109654d6fdacd28810a053348c4d14642da1d075049e6be1ba5216218da
@ -8380,7 +8398,7 @@ __metadata:
languageName: node
linkType: hard
"micromatch@npm:^4.0.4":
"micromatch@npm:^4.0.0, micromatch@npm:^4.0.4":
version: 4.0.5
resolution: "micromatch@npm:4.0.5"
dependencies:
@ -10112,6 +10130,13 @@ __metadata:
languageName: node
linkType: hard
"regenerator-runtime@npm:^0.13.9":
version: 0.13.9
resolution: "regenerator-runtime@npm:0.13.9"
checksum: 65ed455fe5afd799e2897baf691ca21c2772e1a969d19bb0c4695757c2d96249eb74ee3553ea34a91062b2a676beedf630b4c1551cc6299afb937be1426ec55e
languageName: node
linkType: hard
"regexpp@npm:^3.2.0":
version: 3.2.0
resolution: "regexpp@npm:3.2.0"
@ -10965,6 +10990,13 @@ __metadata:
languageName: node
linkType: hard
"tapable@npm:^2.2.0":
version: 2.2.1
resolution: "tapable@npm:2.2.1"
checksum: 3b7a1b4d86fa940aad46d9e73d1e8739335efd4c48322cb37d073eb6f80f5281889bf0320c6d8ffcfa1a0dd5bfdbd0f9d037e252ef972aca595330538aac4d51
languageName: node
linkType: hard
"tar@npm:^6.1.11, tar@npm:^6.1.2":
version: 6.1.11
resolution: "tar@npm:6.1.11"
@ -11270,6 +11302,21 @@ __metadata:
languageName: node
linkType: hard
"ts-loader@npm:^9.2.6":
version: 9.3.1
resolution: "ts-loader@npm:9.3.1"
dependencies:
chalk: ^4.1.0
enhanced-resolve: ^5.0.0
micromatch: ^4.0.0
semver: ^7.3.4
peerDependencies:
typescript: "*"
webpack: ^5.0.0
checksum: 462a8ac315017cf4961dafd2be29d5abe7c3af63c4515e325269f79b9d0212b35c59184d7fd01fc378749c88454752e1599301d2190eb6844ea5fe332de5f695
languageName: node
linkType: hard
"ts-node@npm:^10.4.0, ts-node@npm:^10.8.1":
version: 10.8.2
resolution: "ts-node@npm:10.8.2"