3 votes

Comment dériver la clé et le vecteur initial en Node.js

Je dispose d'une clé partagée dont je dois dériver un iv pour pouvoir la déchiffrer.

Les documents relatifs au chat sur les affaires d'Apple précisent que

Générer la clé dérivée et le vecteur initial Exécuter la clé partagée à travers la fonction de dérivation de clé X9.63 avec la fonction de hachage SHA256. Il en résulte une charge utile de 48 octets. Vos résultats devraient être les suivants rV3qrszd0PMPgeRhNnlOYA==

Voici ce que j'ai essayé. J'ai utilisé les fonctions cryptographiques scryptSync et pbkdf2Sync avec de nombreuses configurations 'salt'. Je ne sais pas si ce sont les bonnes fonctions pour ce travail.

const crypto = require('crypto');

const keyLength = 48;
// sharedKey is a base64 string
const sharedKey = "2lvSJsBO2keUHRfvPG6C1RMUmGpuDbdgNrZ9YD7RYnvAcfgq/fjeYr1p0hWABeif";
// publicKey is a base64 string
const publicKey = "BDiRKNnPiPUb5oala31nkmCaXMB0iyWy3Q93p6fN7vPxEQSUlFVsInkJzPBBqmW1FUIY1KBA3BQb3W3Qv4akZ8kblqbmvupE/EJzPKbROZFBNvxpvVOHHgO2qadmHAjHSg=="

const key1 = crypto.scryptSync(sharedKey, 'salt', keyLength);
console.log(key2.toString('base64'));

const key2 = crypto.pbkdf2Sync(sharedKey, 'salt', 10000, keyLength, 'sha256');
console.log(key2.toString('base64'));

// results should be:
// mAzkYatDlz4SzrCyM23NhgL/+mE3eGgfUz9h1CFPhZM=
// iv: rV3qrszd0PMPgeRhNnlOYA==

Vous trouverez ci-dessous un exemple de code Apple pour la dérivation de la clé et du vecteur initial à l'aide d'une fonction de dérivation de clé X9.63.

    def ITOSP(self, longint, length):
        """ITOSP, short for Integer-to-Octet-String Primitive, converts a non-negative integer
        to an octet string of a specified length. This particular function is defined in the
        PKCS #1 v2.1: RSA Cryptography Standard (June 14, 2002)
        https://www.cryptrec.go.jp/cryptrec_03_spec_cypherlist_files/PDF/pkcs-1v2-12.pdf"""

        hex_string = "%X" % longint
        assert len(hex_string) <= 2 * length, "ITOSP function: Insufficient length for encoding"
        return binascii.a2b_hex(hex_string.zfill(2 * length))

    def KDFX963(self, inbyte_x, shared_data, key_length, hashfunct=sha256, hash_len=32):
        """KDFX963 is a key derivation function (KDF) that takes as input byte sequence inbyte_x
        and additional shared data shared_data and outputs a byte sequence key of length
        key_length. This function is defined in ANSI-X9.63-KDF, and this particular flavor of
        KDF is known as X9.63. You can read more about it from:
        http://www.secg.org/sec1-v2.pdf"""

        assert key_length >= 0, "KDFX963 function: key_length should be positive integer"
        k = key_length / float(hash_len)
        k = int(ceil(k))

        acc_str = ""
        for i in range(1, k+1):
            h = hashfunct()
            h.update(inbyte_x)
            h.update(self.ITOSP(i, 4))
            h.update(shared_data)
            acc_str = acc_str + h.hexdigest()

        return acc_str[:key_length * 2]

4voto

Topaco Points 3235

X9.63 La KDF est une fonction de dérivation de clé, décrite par exemple comme suit aquí y aquí . scrypt et PBKDF2 sont également des KDF, mais différentes, de sorte que le résultat attendu ne peut évidemment pas être reproduit avec elles.

Vous avez donc besoin d'une bibliothèque NodeJS qui supporte X.963 KDF. Si vous n'en trouvez pas, vous pouvez aussi implémenter la vôtre.

X9.63 La KDF attend un secret partagé et une info partagée et détermine une taille des clés comme suit :

  • Créer un compteur de 4 octets c i qui est incrémentée à partir de 0x0000001.
  • Concaténer les données conc i \= secret partagé | c i | Informations partagées
  • Hachage du résultat i \= hash(conc i )
  • Concaténer les hachages 1 | hachage 2 | ... jusqu'à ce qu'une sortie de longueur taille des clés a été généré.

L'algorithme est décrit de manière plus formelle, avec diverses vérifications, dans les liens ci-dessus. Le code Python posté plus loin dans la question met également en œuvre cette logique.

Une implémentation NodeJS possible (en omettant les contrôles de la spécification) est la suivante :

var crypto = require('crypto');

var digest = 'sha256';
var digestLen = 32;

function X963KDF(sharedSecret, sharedInfo, keySize){
  var maxCount = Math.ceil(keySize/digestLen);
  var result = Buffer.allocUnsafe(0);
  for (var count = 1; count < maxCount + 1; count++){
      var counter = Buffer.allocUnsafe(4);
      counter.writeUInt32BE(count, 0);
      var current = Buffer.concat([sharedSecret, counter, sharedInfo]);
      var hash = crypto.createHash(digest).update(current).digest();
      result = Buffer.concat([result, hash]);
  }

  return result.slice(0, keySize);
}

Test :

Dans la question, le secret partagé est affiché, mais pas l'information partagée. Une recherche sur Internet révèle que le problème affiché est décrit, par exemple, comme suit aquí afin que les informations partagées puissent également être déterminées (il serait toutefois préférable que vous ajoutiez cette information à votre question) :

var sharedSecret = Buffer.from('2lvSJsBO2keUHRfvPG6C1RMUmGpuDbdgNrZ9YD7RYnvAcfgq/fjeYr1p0hWABeif', 'base64')
var sharedInfo = Buffer.from('04389128d9cf88f51be686a56b7d6792609a5cc0748b25b2dd0f77a7a7cdeef3f111049494556c227909ccf041aa65b5154218d4a040dc141bdd6dd0bf86a467c91b96a6e6beea44fc42733ca6d139914136fc69bd53871e03b6a9a7661c08c74a', 'hex');

var keyiv = X963KDF(sharedSecret, sharedInfo, 48);
var key = keyiv.slice(0,32).toString('base64');
var iv = keyiv.slice(32, 48).toString('base64');
console.log("Key: ", key); // Key:  mAzkYatDlz4SzrCyM23NhgL/+mE3eGgfUz9h1CFPhZM=
console.log("IV: ", iv); // IV:  rV3qrszd0PMPgeRhNnlOYA==

La clé et l'IV générés sont égaux aux valeurs attendues.

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