无法使用 pkcs11js 生成 32 字节的 AES Secret

Cannot generate 32 bytes AES Secret using pkcs11js

我想用下面的代码生成一个 32 字节的 AES 密钥。我正在使用节点模块 pkcs11js,因为我需要连接到 HSM。但是,当我打印密钥的长度时,它显示的是 8 而不是 32。

var path = require('path');
var pkcs11js = require("pkcs11js");
var crypto = require('crypto');
process.env['SOFTHSM2_CONF'] = path.resolve(__dirname, '../softhsm2.conf');

var pkcs11 = new pkcs11js.PKCS11();
pkcs11.load("/usr/local/Cellar/softhsm/2.4.0/lib/softhsm/libsofthsm2.so");

pkcs11.C_Initialize();

const _pkcs11FindObjects = (pkcs11, pkcs11Session, pkcs11Template) => {
    pkcs11.C_FindObjectsInit(pkcs11Session, pkcs11Template);
    var objs = [];
    var obj = pkcs11.C_FindObjects(pkcs11Session);
    while (obj) {
        objs.push(obj);
        obj = pkcs11.C_FindObjects(pkcs11Session);
    }
    pkcs11.C_FindObjectsFinal(pkcs11Session);
    return objs;
}

const _pkcs11Login = (slotNumber, pin) => {

    let s = null;
    try {
        const slots = pkcs11.C_GetSlotList(true);
        const slot = slots[slotNumber];
        var token_info = pkcs11.C_GetTokenInfo(slot);
        s = pkcs11.C_OpenSession(slot, pkcs11js.CKF_RW_SESSION | pkcs11js.CKF_SERIAL_SESSION);
        pkcs11.C_Login(s, 1, pin);
        return s;
    } catch (e) {
        if (s != null) {
            pkcs11.C_CloseSession(s);
        }
        pkcs11.C_Finalize();
    }

}

const _findAESKey = (session, ski) => {
    var secretKeyHandle = _pkcs11FindObjects(pkcs11, session, [{
            type: pkcs11js.CKA_ID,
            value: ski
        },
        {
            type: pkcs11js.CKA_CLASS,
            value: pkcs11js.CKO_SECRET_KEY
        }
    ]);

    if (secretKeyHandle.length == 1) {
        return secretKeyHandle[0];
    } else {
        return null;
    }
}

const _createAESKey = (session, ski) => {

    let key = _findAESKey(session, ski);
    if (key && key !== null) {
        console.log('Key already exists. No need to re-create');
        return;
    }

    var template = [{
            type: pkcs11js.CKA_ID,
            value: ski
        },
        {
            type: pkcs11js.CKA_CLASS,
            value: pkcs11js.CKO_SECRET_KEY
        },
        {
            type: pkcs11js.CKA_TOKEN,
            value: true
        },
        {
            type: pkcs11js.CKA_LABEL,
            value: "My AES Key"
        },
        {
            type: pkcs11js.CKA_VALUE_LEN,
            value: 32
        },
        {
            type: pkcs11js.CKA_ENCRYPT,
            value: true
        },
        {
            type: pkcs11js.CKA_DECRYPT,
            value: true
        },
        {
            type: pkcs11js.CKA_PRIVATE,
            value: true
        }
    ];
    pkcs11.C_GenerateKey(session, {
        mechanism: pkcs11js.CKM_AES_KEY_GEN
    }, template);
}

let session = _pkcs11Login(0, '98765432');
_createAESKey(session, `9Rf3uJ7CEdKIhUvQu/2KN8hK0Kce0zYfPXSc8xAK4Oc=`);
let key = _findAESKey(session, `9Rf3uJ7CEdKIhUvQu/2KN8hK0Kce0zYfPXSc8xAK4Oc=`);
console.log(`key length: ${key.length}`); //key length: 8

原因是我想使用下面的函数加密数据,它要求密钥长度为 32。

const encryptString = (s, secret) => {
    const iv = crypto.randomBytes(16).toString('hex').slice(0, 16);
    const cipher = crypto.createCipheriv('aes-256-ctr', secret, iv);
    const encrypted = cipher.update(String(s), 'utf8', 'hex') + cipher.final('hex');
    return iv + encrypted;
}

let e = encryptString('shezhuan sauce', key);
console.log(`encrypted string: ${e}`);

以上代码会产生无效密钥长度错误。

根据此处的答案:https://github.com/PeculiarVentures/pkcs11js/issues/34,我可以通过获取 CKA_VALUE 属性来提取密钥,但我需要在密钥生成期间设置以下内容:{ pkcs11js.CKA_EXTRACTABLE, value: true }.我明白这当然违背了 HSM 不暴露秘密的目的。

这里的核心问题是所使用的机制不受 SoftHSM 支持,这就是为什么只使用 get/set 属性方法的原因。可以在不将值设置为可提取的情况下获取值的长度,但前提是 HSM/PKCS11 实现支持该机制。