@stablelib/gcm
Advanced tools
Comparing version 1.0.2 to 2.0.0
// Copyright (C) 2016 Dmitry Chestnykh | ||
// MIT License. See LICENSE file for details. | ||
import { describe, expect, it } from 'vitest'; | ||
import { AES } from "@stablelib/aes"; | ||
@@ -5,0 +6,0 @@ import { GCM } from "./gcm"; |
@@ -8,4 +8,4 @@ // Copyright (C) 2016 Dmitry Chestnykh | ||
import { AEAD } from "@stablelib/aead"; | ||
import { BlockCipher } from "@stablelib/blockcipher"; | ||
import type { AEAD } from "@stablelib/aead"; | ||
import type { BlockCipher } from "@stablelib/blockcipher"; | ||
import { CTR } from "@stablelib/ctr"; | ||
@@ -12,0 +12,0 @@ import { wipe } from "@stablelib/wipe"; |
@@ -1,20 +0,18 @@ | ||
"use strict"; | ||
// Copyright (C) 2016 Dmitry Chestnykh | ||
// MIT License. See LICENSE file for details. | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const aes_1 = require("@stablelib/aes"); | ||
const gcm_1 = require("./gcm"); | ||
const benchmark_1 = require("@stablelib/benchmark"); | ||
const buf8192 = (0, benchmark_1.byteSeq)(8192); | ||
const buf1111 = (0, benchmark_1.byteSeq)(1111); | ||
import { AES } from "@stablelib/aes"; | ||
import { GCM } from "./gcm"; | ||
import { benchmark, report, byteSeq } from "@stablelib/benchmark"; | ||
const buf8192 = byteSeq(8192); | ||
const buf1111 = byteSeq(1111); | ||
const buf0 = new Uint8Array(0); | ||
const key = (0, benchmark_1.byteSeq)(32); | ||
const nonce = (0, benchmark_1.byteSeq)(12); | ||
const cipher = new aes_1.AES(key); | ||
const gcm = new gcm_1.GCM(cipher); | ||
(0, benchmark_1.report)("AES-GCM seal 8K", (0, benchmark_1.benchmark)(() => gcm.seal(nonce, buf8192), buf8192.length)); | ||
(0, benchmark_1.report)("AES-GCM seal 1111", (0, benchmark_1.benchmark)(() => gcm.seal(nonce, buf1111), buf1111.length)); | ||
(0, benchmark_1.report)("AES-GCM seal 8K + AD", (0, benchmark_1.benchmark)(() => gcm.seal(nonce, buf8192, buf8192), buf8192.length * 2)); | ||
(0, benchmark_1.report)("AES-GCM seal 1111 + AD", (0, benchmark_1.benchmark)(() => gcm.seal(nonce, buf1111, buf1111), buf1111.length * 2)); | ||
(0, benchmark_1.report)("AES-GCM seal 0 + AD 8K", (0, benchmark_1.benchmark)(() => gcm.seal(nonce, buf0, buf8192), buf8192.length)); | ||
const key = byteSeq(32); | ||
const nonce = byteSeq(12); | ||
const cipher = new AES(key); | ||
const gcm = new GCM(cipher); | ||
report("AES-GCM seal 8K", benchmark(() => gcm.seal(nonce, buf8192), buf8192.length)); | ||
report("AES-GCM seal 1111", benchmark(() => gcm.seal(nonce, buf1111), buf1111.length)); | ||
report("AES-GCM seal 8K + AD", benchmark(() => gcm.seal(nonce, buf8192, buf8192), buf8192.length * 2)); | ||
report("AES-GCM seal 1111 + AD", benchmark(() => gcm.seal(nonce, buf1111, buf1111), buf1111.length * 2)); | ||
report("AES-GCM seal 0 + AD 8K", benchmark(() => gcm.seal(nonce, buf0, buf8192), buf8192.length)); | ||
const sealed8192 = gcm.seal(nonce, buf8192); | ||
@@ -24,8 +22,8 @@ const sealed1111 = gcm.seal(nonce, buf1111); | ||
const sealed1111ad = gcm.seal(nonce, buf1111, buf1111); | ||
(0, benchmark_1.report)("AES-GCM open 8K", (0, benchmark_1.benchmark)(() => gcm.open(nonce, sealed8192), buf8192.length)); | ||
(0, benchmark_1.report)("AES-GCM open 1111", (0, benchmark_1.benchmark)(() => gcm.open(nonce, sealed1111), buf1111.length)); | ||
(0, benchmark_1.report)("AES-GCM open 8K + AD", (0, benchmark_1.benchmark)(() => gcm.open(nonce, sealed8192ad, buf8192), buf8192.length * 2)); | ||
(0, benchmark_1.report)("AES-GCM open 1111 + AD", (0, benchmark_1.benchmark)(() => gcm.seal(nonce, sealed1111ad, buf1111), buf1111.length * 2)); | ||
report("AES-GCM open 8K", benchmark(() => gcm.open(nonce, sealed8192), buf8192.length)); | ||
report("AES-GCM open 1111", benchmark(() => gcm.open(nonce, sealed1111), buf1111.length)); | ||
report("AES-GCM open 8K + AD", benchmark(() => gcm.open(nonce, sealed8192ad, buf8192), buf8192.length * 2)); | ||
report("AES-GCM open 1111 + AD", benchmark(() => gcm.seal(nonce, sealed1111ad, buf1111), buf1111.length * 2)); | ||
sealed8192[0] ^= sealed8192[0]; | ||
(0, benchmark_1.report)("AES-GCM open (bad)", (0, benchmark_1.benchmark)(() => gcm.open(nonce, sealed8192), buf8192.length)); | ||
report("AES-GCM open (bad)", benchmark(() => gcm.open(nonce, sealed8192), buf8192.length)); | ||
//# sourceMappingURL=gcm.bench.js.map |
/** | ||
* Package gcm implements GCM mode for block ciphers. | ||
*/ | ||
import { AEAD } from "@stablelib/aead"; | ||
import { BlockCipher } from "@stablelib/blockcipher"; | ||
import type { AEAD } from "@stablelib/aead"; | ||
import type { BlockCipher } from "@stablelib/blockcipher"; | ||
export declare const NONCE_LENGTH = 12; | ||
@@ -7,0 +7,0 @@ export declare const TAG_LENGTH = 16; |
@@ -1,12 +0,9 @@ | ||
"use strict"; | ||
// Copyright (C) 2016 Dmitry Chestnykh | ||
// MIT License. See LICENSE file for details. | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.GCM = exports.TAG_LENGTH = exports.NONCE_LENGTH = void 0; | ||
const ctr_1 = require("@stablelib/ctr"); | ||
const wipe_1 = require("@stablelib/wipe"); | ||
const binary_1 = require("@stablelib/binary"); | ||
const constant_time_1 = require("@stablelib/constant-time"); | ||
exports.NONCE_LENGTH = 12; | ||
exports.TAG_LENGTH = 16; | ||
import { CTR } from "@stablelib/ctr"; | ||
import { wipe } from "@stablelib/wipe"; | ||
import { writeUint32BE } from "@stablelib/binary"; | ||
import { equal } from "@stablelib/constant-time"; | ||
export const NONCE_LENGTH = 12; | ||
export const TAG_LENGTH = 16; | ||
/** | ||
@@ -20,3 +17,9 @@ * Galois/Counter Mode AEAD | ||
*/ | ||
class GCM { | ||
export class GCM { | ||
nonceLength = NONCE_LENGTH; | ||
tagLength = TAG_LENGTH; | ||
// Subkey used for authentication. | ||
_subkey; | ||
// Cipher. | ||
_cipher; | ||
/** | ||
@@ -28,4 +31,2 @@ * Creates a new GCM instance with the given block cipher. | ||
constructor(cipher) { | ||
this.nonceLength = exports.NONCE_LENGTH; | ||
this.tagLength = exports.TAG_LENGTH; | ||
if (cipher.blockSize !== 16) { | ||
@@ -78,3 +79,3 @@ throw new Error("GCM supports only 16-byte block cipher"); | ||
// XXX: can avoid allocation by pre-allocating CTR and using setCipher() here. | ||
const ctr = new ctr_1.CTR(this._cipher, counter); | ||
const ctr = new CTR(this._cipher, counter); | ||
ctr.streamXOR(plaintext, result); | ||
@@ -85,4 +86,4 @@ ctr.clean(); | ||
// Cleanup. | ||
(0, wipe_1.wipe)(counter); | ||
(0, wipe_1.wipe)(tagMask); | ||
wipe(counter); | ||
wipe(tagMask); | ||
return result; | ||
@@ -123,3 +124,3 @@ } | ||
// Constant-time compare tags and return null if they differ. | ||
if (!(0, constant_time_1.equal)(calculatedTag, sealed.subarray(sealed.length - this.tagLength, sealed.length))) { | ||
if (!equal(calculatedTag, sealed.subarray(sealed.length - this.tagLength, sealed.length))) { | ||
return null; | ||
@@ -141,12 +142,12 @@ } | ||
// XXX: can avoid allocation by pre-allocating CTR and using setCipher() here. | ||
const ctr = new ctr_1.CTR(this._cipher, counter); | ||
const ctr = new CTR(this._cipher, counter); | ||
ctr.streamXOR(sealed.subarray(0, sealed.length - this.tagLength), result); | ||
ctr.clean(); | ||
// Cleanup. | ||
(0, wipe_1.wipe)(counter); | ||
(0, wipe_1.wipe)(tagMask); | ||
wipe(counter); | ||
wipe(tagMask); | ||
return result; | ||
} | ||
clean() { | ||
(0, wipe_1.wipe)(this._subkey); | ||
wipe(this._subkey); | ||
// Cleaning cipher is caller's responsibility. | ||
@@ -181,6 +182,5 @@ return this; | ||
} | ||
(0, wipe_1.wipe)(lengthsBlock); | ||
wipe(lengthsBlock); | ||
} | ||
} | ||
exports.GCM = GCM; | ||
// Writes big-endian 8-byte bit length of the given byte length | ||
@@ -191,4 +191,4 @@ // into dst at the given offset. | ||
const lo = byteLength << 3; | ||
(0, binary_1.writeUint32BE)(hi, dst, offset + 0); | ||
(0, binary_1.writeUint32BE)(lo, dst, offset + 4); | ||
writeUint32BE(hi, dst, offset + 0); | ||
writeUint32BE(lo, dst, offset + 4); | ||
} | ||
@@ -234,7 +234,7 @@ /** | ||
} | ||
(0, binary_1.writeUint32BE)(z0, a, 0); | ||
(0, binary_1.writeUint32BE)(z1, a, 4); | ||
(0, binary_1.writeUint32BE)(z2, a, 8); | ||
(0, binary_1.writeUint32BE)(z3, a, 12); | ||
writeUint32BE(z0, a, 0); | ||
writeUint32BE(z1, a, 4); | ||
writeUint32BE(z2, a, 8); | ||
writeUint32BE(z3, a, 12); | ||
} | ||
//# sourceMappingURL=gcm.js.map |
@@ -1,8 +0,7 @@ | ||
"use strict"; | ||
// Copyright (C) 2016 Dmitry Chestnykh | ||
// MIT License. See LICENSE file for details. | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const aes_1 = require("@stablelib/aes"); | ||
const gcm_1 = require("./gcm"); | ||
const hex_1 = require("@stablelib/hex"); | ||
import { describe, expect, it } from 'vitest'; | ||
import { AES } from "@stablelib/aes"; | ||
import { GCM } from "./gcm"; | ||
import { encode, decode } from "@stablelib/hex"; | ||
// TODO(dchest): add more test vectors. | ||
@@ -54,12 +53,12 @@ const testVectors = [ | ||
testVectors.forEach(v => { | ||
const cipher = new aes_1.AES((0, hex_1.decode)(v.key)); | ||
const gcm = new gcm_1.GCM(cipher); | ||
const cipher = new AES(decode(v.key)); | ||
const gcm = new GCM(cipher); | ||
let sealed; | ||
if (v.ad) { | ||
sealed = gcm.seal((0, hex_1.decode)(v.nonce), (0, hex_1.decode)(v.plaintext), (0, hex_1.decode)(v.ad)); | ||
sealed = gcm.seal(decode(v.nonce), decode(v.plaintext), decode(v.ad)); | ||
} | ||
else { | ||
sealed = gcm.seal((0, hex_1.decode)(v.nonce), (0, hex_1.decode)(v.plaintext)); | ||
sealed = gcm.seal(decode(v.nonce), decode(v.plaintext)); | ||
} | ||
expect((0, hex_1.encode)(sealed)).toBe(v.result); | ||
expect(encode(sealed)).toBe(v.result); | ||
}); | ||
@@ -69,14 +68,14 @@ }); | ||
testVectors.forEach(v => { | ||
const cipher = new aes_1.AES((0, hex_1.decode)(v.key)); | ||
const gcm = new gcm_1.GCM(cipher); | ||
const cipher = new AES(decode(v.key)); | ||
const gcm = new GCM(cipher); | ||
let plaintext; | ||
if (v.ad) { | ||
plaintext = gcm.open((0, hex_1.decode)(v.nonce), (0, hex_1.decode)(v.result), (0, hex_1.decode)(v.ad)); | ||
plaintext = gcm.open(decode(v.nonce), decode(v.result), decode(v.ad)); | ||
} | ||
else { | ||
plaintext = gcm.open((0, hex_1.decode)(v.nonce), (0, hex_1.decode)(v.result)); | ||
plaintext = gcm.open(decode(v.nonce), decode(v.result)); | ||
} | ||
expect(plaintext).not.toBeNull(); | ||
if (plaintext) { | ||
expect((0, hex_1.encode)(plaintext)).toBe(v.plaintext); | ||
expect(encode(plaintext)).toBe(v.plaintext); | ||
} | ||
@@ -87,8 +86,8 @@ }); | ||
const v = testVectors[0]; | ||
const sealed = (0, hex_1.decode)(v.result); | ||
const ad = v.ad ? (0, hex_1.decode)(v.ad) : undefined; | ||
const sealed = decode(v.result); | ||
const ad = v.ad ? decode(v.ad) : undefined; | ||
sealed[0] ^= sealed[0]; | ||
const cipher = new aes_1.AES((0, hex_1.decode)(v.key)); | ||
const gcm = new gcm_1.GCM(cipher); | ||
const plaintext = gcm.open((0, hex_1.decode)(v.nonce), sealed, ad); | ||
const cipher = new AES(decode(v.key)); | ||
const gcm = new GCM(cipher); | ||
const plaintext = gcm.open(decode(v.nonce), sealed, ad); | ||
expect(plaintext).toBeNull(); | ||
@@ -98,8 +97,8 @@ }); | ||
const v = testVectors[0]; | ||
const sealed = (0, hex_1.decode)(v.result); | ||
const ad = v.ad ? (0, hex_1.decode)(v.ad) : undefined; | ||
const sealed = decode(v.result); | ||
const ad = v.ad ? decode(v.ad) : undefined; | ||
sealed[sealed.length - 1] ^= sealed[sealed.length - 1]; | ||
const cipher = new aes_1.AES((0, hex_1.decode)(v.key)); | ||
const gcm = new gcm_1.GCM(cipher); | ||
const plaintext = gcm.open((0, hex_1.decode)(v.nonce), sealed, ad); | ||
const cipher = new AES(decode(v.key)); | ||
const gcm = new GCM(cipher); | ||
const plaintext = gcm.open(decode(v.nonce), sealed, ad); | ||
expect(plaintext).toBeNull(); | ||
@@ -109,32 +108,32 @@ }); | ||
const v = testVectors[0]; | ||
const cipher = new aes_1.AES((0, hex_1.decode)(v.key)); | ||
const gcm = new gcm_1.GCM(cipher); | ||
const plaintext = (0, hex_1.decode)(v.plaintext); | ||
const ad = v.ad ? (0, hex_1.decode)(v.ad) : undefined; | ||
const cipher = new AES(decode(v.key)); | ||
const gcm = new GCM(cipher); | ||
const plaintext = decode(v.plaintext); | ||
const ad = v.ad ? decode(v.ad) : undefined; | ||
const dst = new Uint8Array(plaintext.length + gcm.tagLength); | ||
const sealed = gcm.seal((0, hex_1.decode)(v.nonce), (0, hex_1.decode)(v.plaintext), ad, dst); | ||
expect((0, hex_1.encode)(dst)).toBe((0, hex_1.encode)(sealed)); | ||
expect((0, hex_1.encode)(sealed)).toBe(v.result); | ||
const sealed = gcm.seal(decode(v.nonce), decode(v.plaintext), ad, dst); | ||
expect(encode(dst)).toBe(encode(sealed)); | ||
expect(encode(sealed)).toBe(v.result); | ||
}); | ||
it("should throw if seal got dst of wrong length", () => { | ||
const v = testVectors[0]; | ||
const cipher = new aes_1.AES((0, hex_1.decode)(v.key)); | ||
const gcm = new gcm_1.GCM(cipher); | ||
const plaintext = (0, hex_1.decode)(v.plaintext); | ||
const ad = v.ad ? (0, hex_1.decode)(v.ad) : undefined; | ||
const cipher = new AES(decode(v.key)); | ||
const gcm = new GCM(cipher); | ||
const plaintext = decode(v.plaintext); | ||
const ad = v.ad ? decode(v.ad) : undefined; | ||
const dst = new Uint8Array(plaintext.length + gcm.tagLength - 1); // wrong length | ||
expect(() => gcm.seal((0, hex_1.decode)(v.nonce), (0, hex_1.decode)(v.plaintext), ad, dst)).toThrowError(/length/); | ||
expect(() => gcm.seal(decode(v.nonce), decode(v.plaintext), ad, dst)).toThrowError(/length/); | ||
}); | ||
it("should open to dst it is provided", () => { | ||
const v = testVectors[0]; | ||
const cipher = new aes_1.AES((0, hex_1.decode)(v.key)); | ||
const gcm = new gcm_1.GCM(cipher); | ||
const sealed = (0, hex_1.decode)(v.result); | ||
const ad = v.ad ? (0, hex_1.decode)(v.ad) : undefined; | ||
const cipher = new AES(decode(v.key)); | ||
const gcm = new GCM(cipher); | ||
const sealed = decode(v.result); | ||
const ad = v.ad ? decode(v.ad) : undefined; | ||
const dst = new Uint8Array(sealed.length - gcm.tagLength); | ||
const plaintext = gcm.open((0, hex_1.decode)(v.nonce), (0, hex_1.decode)(v.result), ad, dst); | ||
const plaintext = gcm.open(decode(v.nonce), decode(v.result), ad, dst); | ||
expect(plaintext).not.toBeNull(); | ||
if (plaintext) { | ||
expect((0, hex_1.encode)(dst)).toBe((0, hex_1.encode)(plaintext)); | ||
expect((0, hex_1.encode)(plaintext)).toBe(v.plaintext); | ||
expect(encode(dst)).toBe(encode(plaintext)); | ||
expect(encode(plaintext)).toBe(v.plaintext); | ||
} | ||
@@ -144,10 +143,10 @@ }); | ||
const v = testVectors[0]; | ||
const cipher = new aes_1.AES((0, hex_1.decode)(v.key)); | ||
const gcm = new gcm_1.GCM(cipher); | ||
const sealed = (0, hex_1.decode)(v.result); | ||
const ad = v.ad ? (0, hex_1.decode)(v.ad) : undefined; | ||
const cipher = new AES(decode(v.key)); | ||
const gcm = new GCM(cipher); | ||
const sealed = decode(v.result); | ||
const ad = v.ad ? decode(v.ad) : undefined; | ||
const dst = new Uint8Array(sealed.length - gcm.tagLength + 1); // wrong length | ||
expect(() => gcm.open((0, hex_1.decode)(v.nonce), (0, hex_1.decode)(v.result), ad, dst)).toThrowError(/length/); | ||
expect(() => gcm.open(decode(v.nonce), decode(v.result), ad, dst)).toThrowError(/length/); | ||
}); | ||
}); | ||
//# sourceMappingURL=gcm.test.js.map |
{ | ||
"name": "@stablelib/gcm", | ||
"version": "1.0.2", | ||
"version": "2.0.0", | ||
"description": "GCM authenticated encryption mode with associated data (AEAD)", | ||
"main": "./lib/gcm.js", | ||
"type": "module", | ||
"typings": "./lib/gcm.d.ts", | ||
@@ -18,19 +19,19 @@ "author": "Dmitry Chestnykh", | ||
"build": "tsc", | ||
"test": "jasmine JASMINE_CONFIG_PATH=../../configs/jasmine.json", | ||
"test": "vitest run", | ||
"bench": "node ./lib/gcm.bench.js" | ||
}, | ||
"dependencies": { | ||
"@stablelib/aead": "^1.0.1", | ||
"@stablelib/binary": "^1.0.1", | ||
"@stablelib/blockcipher": "^1.0.1", | ||
"@stablelib/constant-time": "^1.0.1", | ||
"@stablelib/ctr": "^1.0.2", | ||
"@stablelib/wipe": "^1.0.1" | ||
"@stablelib/aead": "^2.0.0", | ||
"@stablelib/binary": "^2.0.0", | ||
"@stablelib/blockcipher": "^2.0.0", | ||
"@stablelib/constant-time": "^2.0.0", | ||
"@stablelib/ctr": "^2.0.0", | ||
"@stablelib/wipe": "^2.0.0" | ||
}, | ||
"devDependencies": { | ||
"@stablelib/aes": "^1.0.1", | ||
"@stablelib/benchmark": "^1.0.1", | ||
"@stablelib/hex": "^1.0.1" | ||
"@stablelib/aes": "^2.0.0", | ||
"@stablelib/benchmark": "^2.0.0", | ||
"@stablelib/hex": "^2.0.0" | ||
}, | ||
"gitHead": "a402dc74f45c6a93a777a0e2840ce50ba68c3010" | ||
"gitHead": "ecfe9109b3c05419fd3ffc16da6c8255b08ad64f" | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
16
883
Yes
57454
+ Added@stablelib/aead@2.0.0(transitive)
+ Added@stablelib/binary@2.0.1(transitive)
+ Added@stablelib/blockcipher@2.0.0(transitive)
+ Added@stablelib/constant-time@2.0.1(transitive)
+ Added@stablelib/ctr@2.0.1(transitive)
+ Added@stablelib/int@2.0.1(transitive)
+ Added@stablelib/wipe@2.0.1(transitive)
- Removed@stablelib/aead@1.0.1(transitive)
- Removed@stablelib/binary@1.0.1(transitive)
- Removed@stablelib/blockcipher@1.0.1(transitive)
- Removed@stablelib/constant-time@1.0.1(transitive)
- Removed@stablelib/ctr@1.0.2(transitive)
- Removed@stablelib/int@1.0.1(transitive)
- Removed@stablelib/wipe@1.0.1(transitive)
Updated@stablelib/aead@^2.0.0
Updated@stablelib/binary@^2.0.0
Updated@stablelib/ctr@^2.0.0
Updated@stablelib/wipe@^2.0.0