2 votes

WebCryptoApi : Cannot wrap&unwrap aes-gcm key into&from "jwk" format with "encrypt" and "decrypt" active

Je génère une clé pour crypter les données, puis je l'enveloppe en utilisant une clé principale et je la stocke avec les données cryptées. Tout va bien lorsque je l'enveloppe dans raw mais lorsqu'il est emballé comme jwk Je reçois l'erreur DOMException: Data provided to an operation does not meet requirements .

Cela fonctionne lorsque l'on spécifie qu'une clé est utilisée soit pour le cryptage, soit pour le décryptage, mais pas lorsque les deux sont spécifiés comme utilisation de la clé.

let wrapAlgo = {
    name: "AES-KW",
    length: 256
};
let encAlgo = {
    name:"AES-GCM",
    length:256
}
let format = "jwk";
let extractable=true;
let keyUsages = ["encrypt", "decrypt"];

let kek = await crypto.subtle.generateKey(
    wrapAlgo, 
    false, 
    ["wrapKey", "unwrapKey"]
);

let key = await window.crypto.subtle.generateKey(
    encAlgo,
    extractable, // the key is extractable (i.e. can be used in exportKey)
    keyUsages
);
console.log("key", key);

let wrappedKey = await crypto.subtle.wrapKey(
    format,
    key,
    kek,
    wrapAlgo
);
console.log("wrappedKey", wrappedKey);

let unwrappedKey = await crypto.subtle.unwrapKey(
    format,
    wrappedKey,
    kek,
    wrapAlgo,
    encAlgo,
    extractable,
    keyUsages
);
console.log("key", await crypto.subtle.exportKey("jwk", unwrappedKey));

1voto

Topaco Points 3235

AES-KW est un algorithme d'enveloppement de clé décrit dans RFC3394 . L'algorithme est utilisé pour envelopper, c'est-à-dire chiffrer, une clé. L'entrée, c'est-à-dire la clé à crypter, doit être un multiple entier de 8 octets, s. aussi aquí .

La clé à crypter est passée en SubtleCrypto.wrapKey() dans le 2ème paramètre key comme CryptoKey et doivent donc être exportés avant le cryptage proprement dit. À cette fin, le format dans lequel la clé est exportée est spécifié dans le 1er paramètre format :

const result = crypto.subtle.wrapKey(format, key, wrappingKey, wrapAlgo);

Dans l'exemple affiché, la clé à envelopper est une clé de 32 octets pour AES-256. Dans raw la clé satisfait donc au critère de longueur de l'AES-KW. Dans jwk Toutefois, le critère de la longueur n'est généralement pas respecté :
Si la clé exportée dans jwk est sérialisé, il a une longueur pour l'utilisation de la clé ["encrypt"] ou ["decrypt"] qui se trouve être un multiple entier de 8 octets (112 octets), alors que ce n'est pas le cas pour les utilisations de la clé ["encrypt", "decrypt"] (122 octets) :

(async () => {
    async function getLength(keyUsages) {  
        var key = await window.crypto.subtle.generateKey(
            {name:"AES-GCM", length: 256},
            true, 
            keyUsages
        );
        var expkey = await crypto.subtle.exportKey("jwk", key)
        var expkeySerLen = JSON.stringify(expkey).length;
        return {KeyUsages: keyUsages, length: expkeySerLen, lenMod8: expkeySerLen % 8}; 
    }
    console.log(await getLength(["encrypt"]));            // works
    console.log(await getLength(["decrypt"]));            // works
    console.log(await getLength(["encrypt", "decrypt"])); // doesn't work
})();

C'est très probablement la raison pour laquelle le code avec l'utilisation de la clé ["encrypt"] ou ["decrypt"] est exécuté, mais pas le code pour les utilisations clés ["encrypt", "decrypt"] .

L'essentiel est que l'AES-KW fonctionne. de manière fiable pour le raw mais pas pour le format jwk format.

Cependant, le jwk peut être utilisé dans SubtleCrypto.wrapKey() pour d'autres algorithmes d'enveloppement, tels que AES-GCM :

(async () => {

    let encAlgo = {
        name:"AES-GCM",
        length:256
    };
    let wrapAlgo = {
        name:"AES-GCM",
        length:256
    };
    let aesGcmParams = {
        name:"AES-GCM",
        iv: window.crypto.getRandomValues(new Uint8Array(12))
    };
    let format = "jwk";
    let extractable=true;
    let keyUsages = ["encrypt", "decrypt"];

    let kek = await crypto.subtle.generateKey(
        wrapAlgo, 
        false, 
        ["wrapKey", "unwrapKey"]
    );

    let key = await window.crypto.subtle.generateKey(
        encAlgo,
        extractable, // the key is extractable (i.e. can be used in exportKey)
        keyUsages
    );
    console.log("key (CryptoKey)", key);
    console.log("key (jwk)", await crypto.subtle.exportKey("jwk", key));

    let wrappedKey = await crypto.subtle.wrapKey(
        format,
        key,
        kek,
        aesGcmParams
    );
    console.log("wrappedKey (ArrayBuffer)", wrappedKey);

    let unwrappedKey = await crypto.subtle.unwrapKey(
        format,
        wrappedKey,
        kek,
        aesGcmParams,
        encAlgo,
        extractable,
        keyUsages
    );
    console.log("unwrappedKey (jwk) ", await crypto.subtle.exportKey("jwk", unwrappedKey));

})();

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X