【问题标题】:Webcrypto PBKDF2-SHA1Webcrypto PBKDF2-SHA1
【发布时间】:2020-08-24 17:19:59
【问题描述】:

我在使用带有 Webcrypto 的 PBKDF2 时遇到问题。我想将 PBKDF2 与 SHA-1 算法一起使用。目前,我有,

const ENCODING = "utf-8";
const HMACSHA1 = {name: "HMAC", "hash" : "SHA-1"};
const PBKDF2SHA1 = {name: "PBKDF2", "hash": "SHA-1"};

// str2binb takes a string and outputs an ArrayBuffer

async function pbkdf2_generate_key_from_string(string) { //  Working
  return crypto.subtle.importKey(
    "raw",
    str2binb(string),
    PBKDF2SHA1,
    false,
    ["deriveKey", "deriveBits"],
  );
}

async function pbkdf2_derive_salted_key(key, salt, iterations) {  // Not working
  return crypto.subtle.deriveKey(
    {
      "name": "PBKDF2",
      "salt": salt,
      "iterations": iterations,
      "hash": "SHA-1",
      "length": 160
    },
    key,
    {
      "name": "HMAC"
      "hash": "SHA-1",
      "length": 160
    },
    true,
    [ "encrypt", "decrypt"]
  );
}

但是我知道我一定是用错了,因为它是受支持的密钥派生算法,根据 Mozilla 的精彩文档,derivedKeyAlgorithm HMAC 和 HMAC-SHA1 都受支持。我也可以直接使用AES-GCM

我在尝试时收到的错误消息,

salt = b64binb("QSXCR+Q6sek8bf92"); // ArrayBuffer
key = await pbkdf2_generate_key_from_string("pencil");
x = await pbkdf2_derive_salted_key(key, salt, 4096)

Uncaught DOMException: Cannot create a key using the specified key usages.

注意:我知道不再推荐使用 SHA1,这是为了支持旧版。

注意 2:当我将上面的内容替换为时,它可以工作,

async function pbkdf2_derive_salted_key(key, data, salt, iterations) {  // Not working
  return crypto.subtle.deriveKey(
    {
      "name": "PBKDF2",
      salt: salt,
      "iterations": iterations,
      "hash": "SHA-1",
    },
    key,
    {
      "name": "AES-GCM",
      "length": 256
    },
    true,
    [ "encrypt", "decrypt"]
  );
}

谢谢。

【问题讨论】:

    标签: javascript cryptography pbkdf2 hmacsha1 webcrypto


    【解决方案1】:

    deriveKey中,参数keyUsages必须改为["sign", "verify"]。然后代码工作(因为b64binbstr2binb 没有发布,下面的代码使用适当的替代品):

    const b64binb = base64String => Uint8Array.from(atob(base64String), c => c.charCodeAt(0));
    const str2binb = str => new TextEncoder().encode(str);
    const buf2hex = buffer => Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).join('');
    
    async function pbkdf2_generate_key_from_string(string) { 
        return crypto.subtle.importKey(
            "raw",
            str2binb(string),
            {
                name: "PBKDF2",
            },
            false,
            ["deriveKey", "deriveBits"], 
        );
    }
    
    async function pbkdf2_derive_salted_key(key, salt, iterations) {  
        return crypto.subtle.deriveKey(
            {
                name: "PBKDF2",
                salt: salt,
                iterations: iterations,
                hash: {name: "SHA-1"}
            },
            key,
            {
                name: "HMAC",
                hash: "SHA-1",
                length: 160
            },
            true,
            ["sign", "verify"] // <--------------------- Fix!
        );
    }
    
    async function test(){
        salt = b64binb("QSXCR+Q6sek8bf92"); // ArrayBuffer
        key = await pbkdf2_generate_key_from_string("pencil");
        x = await pbkdf2_derive_salted_key(key, salt, 4096)
    
        console.log(buf2hex(await window.crypto.subtle.exportKey("raw", x)));
    }
    
    test();

    使用此密钥,window.crypto.subtle.sign 使用 HMAC-SHA1 创建签名。

    更新:

    由于在SubtleCrypto 中通常指定使用密钥,所以["encrypt", "decrypt"] 必须作为keyUsages 用于AES-GCM 参数和["sign", "verify"] 用于HMAC-SHA。

    为什么 ["encrypt", "decrypt"] 用于 AES-GCM? AES-GCM 用于加密/解密消息:AES 描述了一个block cipher(允许加密一个单个块)和GCM mode of operation(允许加密更多而不是单个块)。 GCM 提供机密性、真实性和完整性。

    为什么要为 HMAC-SHA 使用 ["sign", "verify"]? HMAC 用于签名/验证 消息:某些操作模式(例如CBC)仅提供机密性。为了另外提供真实性和完整性,可以使用MAC 对消息进行签名(例如HMAC,它是基于cryptographic hash function 的特定类型的MAC,例如SHA 系列之一) . MAC 通常是根据密文而不是明文 (Encrypt-then-MAC) 计算得出的。关于 SHA1 漏洞,请参阅 HMAC-SHA1 和 HMAC-SHA256 herehere 的比较。

    【讨论】:

    • 谢谢!我刚刚运行它,它的工作原理。如果你有时间做另一个问题,哈哈,为什么它会在AES-GCMHMAC-SHA1 之间变化?
    • @Justin - AES-GCM 用于加密/解密,HMAC-SHA 用于签名/验证,请参阅我的答案中的更新部分。
    • 感谢! @Topaco
    猜你喜欢
    • 2011-01-28
    • 2019-05-03
    • 2014-10-01
    • 2011-06-23
    • 2019-12-23
    • 1970-01-01
    • 1970-01-01
    • 2016-01-13
    • 2016-07-13
    相关资源
    最近更新 更多