Closed teetjes closed 5 years ago
import * as graphene from "graphene-pk11";
const library = "/usr/local/lib/softhsm/libsofthsm2.so";
const pin = "12345";
const slotIndex = 0;
const blockSize = 16;
function main() {
const softhsm = graphene.Module.load(library);
softhsm.initialize();
try {
const slot = softhsm.getSlots(slotIndex);
const session = slot.open(graphene.SessionFlag.SERIAL_SESSION);
session.login(pin);
//#region Generate AES key
const key = session.generateKey(graphene.KeyGenMechanism.AES, {
private: false,
token: false,
class: graphene.ObjectClass.SECRET_KEY,
valueLen: 16,
encrypt: true,
decrypt: true,
}).toType<graphene.SecretKey>();
console.log("AES key created");
//#endregion
const params = new graphene.AesGcm240Params(Buffer.from("123456789012"), Buffer.from("additional"));
//#region Encrypt
const cipher = session.createCipher({
name: "AES_GCM",
params,
}, key);
const cipherBlocks: Buffer[] = [];
cipherBlocks.push(cipher.update(Buffer.from("123456789012345678901234567890")));
cipherBlocks.push(cipher.update(Buffer.from("123456789012345678901234567890")));
cipherBlocks.push(cipher.update(Buffer.from("123456789012345678901234567890")));
cipherBlocks.push(cipher.final());
const encryptedMessage = Buffer.concat(cipherBlocks);
console.log("Encrypted message:", encryptedMessage.toString("hex"));
//#endregion
//#region Decrypt
const decipher = session.createDecipher({
name: "AES_GCM",
params,
}, key, encryptedMessage.length);
const decipherBlocks: Buffer[] = [];
let offset = 0;
while (offset < encryptedMessage.length) {
const block = encryptedMessage.slice(offset, offset + blockSize);
decipherBlocks.push(decipher.update(block));
offset += block.length;
}
decipherBlocks.push(decipher.final());
console.log("Decrypted message:", Buffer.concat(decipherBlocks).toString());
//#endregion
}
finally {
softhsm.finalize();
}
}
main();
AES key created
Encrypted message: 49751226b55143d6712575924f4c4be51fc2403099499fbe4200e0017c8520552931953e1fc894e59da67e41676028fd04ce7ec75b96b527d159a83d04fc306b79d4eaeb0c7bb9943b954a0eb2768fd32bf40d92672bc91a536564136e048e7decf3afedcd13643d3862
Decrypted message: 123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
AEG GCM mechanism returns decrypted message in Final operation only. It doesn't return decrypted blocks from Update operation as AES CBC does.
createDecipher
method allows setting the output buffer size
public createDecipher(alg: MechanismType, key: Key, blockSize?: number): Decipher;
Thank you. That does indeed work.
I did not really look at changing blocksize. Reading blockSize I immediately think of the block cipher block size aka 128, so its a bit of a confusing name I guess.
If you try to encrypt on SoftHSM and encrypt with AES_GCM more than the block size of data, i.e. more than 16 byte you'll receive a ciphertext as intended.
When you subsequently try do decrypt it, decryption fails, because the buffer that is being allocated in final() (https://github.com/PeculiarVentures/graphene/blob/master/src/crypto/decipher.ts#L43) is not large enough to hold the whole plaintext.
I guess this is due to the fact that for other modes of operation the update() function already processes most of the ciphertext/plaintext, which is not possible for GCM since GCM needs to check the AuthTag on the whole ciphertext, thus shouldn't process ciphertext prior to final() being called
Using latest graphene and SoftHSM 2.4.0