无法使用pkcs11js生成32字节AES机密

时间:2018-08-06 10:38:29

标签: node.js cryptography pkcs#11

我想用下面的代码生成一个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}`);

上面的代码将产生无效的密钥长度错误。

2 个答案:

答案 0 :(得分:1)

基于这里的答案:https://github.com/PeculiarVentures/pkcs11js/issues/34,我能够通过获取CKA_VALUE属性来提取秘密密钥,但是我需要在密钥生成过程中设置以下内容:{ pkcs11js.CKA_EXTRACTABLE, value: true }。我了解这当然会破坏HSM的目的,即不公开秘密。

答案 1 :(得分:1)

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