Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
/* Slicing an ArrayBuffer in a browser is suboptimal.
* It makes a copy.s
* So I just make a new view for the length of the frame.
*/
const framePlaintext = new Uint8Array(
plaintext.buffer,
(sequenceNumber - 1) * frameLength,
isFinalFrame ? finalFrameLength : frameLength
)
const cipherBufferAndAuthTag = await getSubtleEncrypt(frameIv, messageAdditionalData)(framePlaintext)
bodyContent.push(frameHeader, cipherBufferAndAuthTag)
}
const result = concatBuffers(
header,
headerAuthIv,
headerAuthTag,
...bodyContent
)
dispose()
if (typeof subtleSign === 'function') {
const signatureArrayBuffer = await subtleSign(result)
const derSignature = raw2der(new Uint8Array(signatureArrayBuffer), material.suite)
const signatureInfo = serializeSignatureInfo(derSignature)
return { result: concatBuffers(result, signatureInfo), messageHeader }
} else {
return { result: result, messageHeader }
}
keyNamespace: string,
keyName: string,
material: NodeDecryptionMaterial,
wrappingMaterial: NodeRawAesMaterial,
edk: EncryptedDataKey,
aad: Buffer
): NodeDecryptionMaterial {
const { authTag, ciphertext, iv } = rawAesEncryptedParts(material.suite, keyName, edk)
const { encryption } = wrappingMaterial.suite
// createDecipheriv is incorrectly typed in @types/node. It should take key: CipherKey, not key: BinaryLike
const decipher = createDecipheriv(encryption, wrappingMaterial.getUnencryptedDataKey() as any, iv)
.setAAD(aad)
.setAuthTag(authTag)
// Buffer.concat will use the shared buffer space, and the resultant buffer will have a byteOffset...
const unencryptedDataKey = concatBuffers(decipher.update(ciphertext), decipher.final())
const trace = { keyNamespace, keyName, flags: decryptFlags }
return material.setUnencryptedDataKey(unencryptedDataKey, trace)
}
sequenceNumber += 1
const { clearBlob, frameInfo } = await framedDecrypt({ buffer, getSubtleDecrypt, headerInfo, readPos })
/* Precondition: The sequenceNumber is required to monotonically increase, starting from 1.
* This is to avoid a bad actor from abusing the sequence number on un-signed algorithm suites.
* If the frame size matched the data format (say NDJSON),
* then the data could be significantly altered just by rearranging the frames.
* Non-framed data returns a sequenceNumber of 1.
*/
needs(frameInfo.sequenceNumber === sequenceNumber, 'Encrypted body sequence out of order.')
clearBuffers.push(clearBlob)
readPos = frameInfo.readPos
if (frameInfo.isFinalFrame) {
const plaintext = concatBuffers(...clearBuffers)
return { plaintext, readPos }
}
}
}
keyNamespace: string,
keyName: string,
material: NodeEncryptionMaterial,
aad: Buffer,
wrappingMaterial: NodeRawAesMaterial
): NodeEncryptionMaterial {
const { encryption, ivLength } = wrappingMaterial.suite
const iv = randomBytes(ivLength)
const wrappingDataKey = wrappingMaterial.getUnencryptedDataKey()
const dataKey = unwrapDataKey(material.getUnencryptedDataKey())
const cipher = createCipheriv(encryption, wrappingDataKey, iv)
.setAAD(aad)
// Buffer.concat will use the shared buffer space, and the resultant buffer will have a byteOffset...
const ciphertext = concatBuffers(cipher.update(dataKey), cipher.final())
const authTag = cipher.getAuthTag()
const edk = rawAesEncryptedDataKey(
keyNamespace,
keyName,
iv,
ciphertext,
authTag
)
return material.addEncryptedDataKey(edk, encryptFlags)
}
async function aesGcmUnwrapKey (
keyNamespace: string,
keyName: string,
material: WebCryptoDecryptionMaterial,
wrappingMaterial: WebCryptoRawAesMaterial,
edk: EncryptedDataKey,
aad: Uint8Array
): Promise {
const { suite } = material
const { iv, ciphertext, authTag } = rawAesEncryptedParts(suite, keyName, edk)
const backend = await getWebCryptoBackend()
const KdfGetSubtleDecrypt = getSubtleFunction(wrappingMaterial, backend, 'decrypt')
const info = new Uint8Array()
const buffer = await KdfGetSubtleDecrypt(info)(iv, aad)(concatBuffers(ciphertext, authTag))
const trace = { keyNamespace, keyName, flags: decryptFlags }
material.setUnencryptedDataKey(new Uint8Array(buffer), trace)
return importForWebCryptoDecryptionMaterial(material)
}
function rawAesEncryptedDataKey (
keyNamespace: string,
keyName: string,
iv: Uint8Array,
ciphertext: Uint8Array,
authTag: Uint8Array
): EncryptedDataKey {
const ivLength = iv.byteLength
const authTagBitLength = authTag.byteLength * 8
const encryptedDataKey = concatBuffers(ciphertext, authTag)
const providerId = keyNamespace
const rawInfo = concatBuffers(fromUtf8(keyName), uInt32BE(authTagBitLength), uInt32BE(ivLength), iv)
const providerInfo = toUtf8(rawInfo)
return new EncryptedDataKey({ encryptedDataKey, providerId, providerInfo, rawInfo })
}
}
}
const result = concatBuffers(
header,
headerAuthIv,
headerAuthTag,
...bodyContent
)
dispose()
if (typeof subtleSign === 'function') {
const signatureArrayBuffer = await subtleSign(result)
const derSignature = raw2der(new Uint8Array(signatureArrayBuffer), material.suite)
const signatureInfo = serializeSignatureInfo(derSignature)
return { result: concatBuffers(result, signatureInfo), messageHeader }
} else {
return { result: result, messageHeader }
}
}