diff --git a/src/crypto/aes.js b/src/crypto/aes.js index 89d9785f..3e34d740 100644 --- a/src/crypto/aes.js +++ b/src/crypto/aes.js @@ -2,6 +2,9 @@ import CID from '../cid.js' import random from 'js-crypto-random' import aes from 'js-crypto-aes' +/** + * @param {number} value + */ const enc32 = value => { value = +value const buff = new Uint8Array(4) @@ -12,6 +15,9 @@ const enc32 = value => { return buff } +/** + * @param {Uint8Array} buffer + */ const readUInt32LE = (buffer) => { const offset = buffer.byteLength - 4 return ((buffer[offset]) | @@ -20,18 +26,32 @@ const readUInt32LE = (buffer) => { (buffer[offset + 3] * 0x1000000) } +/** + * @param {Uint8Array[]} buffers + */ const concat = buffers => Uint8Array.from(buffers.map(b => [...b]).flat()) +/** + * @template {'aes-gcm' | 'aes-cbc' | 'aes-ctr'} Name + * @template {number} Code + * @param {Object} options + * @param {Name} options.name + * @param {Code} options.code + * @param {number} options.ivsize + */ const mkcrypto = ({ name, code, ivsize }) => { + // Line below does a type cast, because type checker can't infer that + // `toUpperCase` will result in desired string literal. + const cyperType = /** @type {import('js-crypto-aes/dist/params').cipherTypes} */(name.toUpperCase()) /** * @param {Object} options - * @param {Object} options.value * @param {Uint8Array} options.key + * @param {Object} options.value * @param {Uint8Array} options.value.bytes * @param {Uint8Array} options.value.iv */ const decrypt = async ({ key, value: { iv, bytes } }) => { - bytes = await aes.decrypt(bytes, key, { name: name.toUpperCase(), iv, tagLength: 16 }) + bytes = await aes.decrypt(bytes, key, { name: cyperType, iv, tagLength: 16 }) const len = readUInt32LE(bytes.subarray(0, 4)) const cid = CID.decode(bytes.subarray(4, 4 + len)) bytes = bytes.subarray(4 + len) @@ -47,10 +67,19 @@ const mkcrypto = ({ name, code, ivsize }) => { const len = enc32(cid.bytes.byteLength) const iv = random.getRandomBytes(ivsize) const msg = concat([len, cid.bytes, bytes]) - bytes = await aes.encrypt(msg, key, { name: name.toUpperCase(), iv, tagLength: 16 }) + bytes = await aes.encrypt(msg, key, { name: cyperType, iv, tagLength: 16 }) return { bytes, iv, code } } - return { encrypt, decrypt, code, name: name.toLowerCase(), ivsize } + + return { + code, + // Note: Do a type cast becasue `toLowerCase()` turns liternal type + // into a string. + name: /** @type {Name} */(name.toLowerCase()), + encrypt, + decrypt, + ivsize + } } const gcm = mkcrypto({ name: 'aes-gcm', code: 0x1401, ivsize: 12 }) diff --git a/tsconfig.json b/tsconfig.json index 4ce54b0e..104133d7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -16,7 +16,7 @@ "strict": true, "alwaysStrict": true, "esModuleInterop": true, - "target": "ES2018", + "target": "ES2019", "moduleResolution": "node", "declaration": true, "declarationMap": true,