Chiffrer avec le module Crypto Node.js et décrypter avec Java (dans l'application Android)
Recherche d'un moyen de crypter les données (principalement des chaînes de caractères) dans le nœud et décrypter dans une application android (java).
L'ont fait avec succès dans chacun (crypter/décrypter un nœud, et de chiffrer/déchiffrer en java) mais ne semble pas possible de faire fonctionner entre eux.
Éventuellement, je ne suis pas le cryptage/décryptage de la même façon, mais chaque bibliothèque dans chaque langue a des noms différents pour les mêmes choses...
Toute aide appréciée.
voici un code:
Node.js
var crypto = require('crypto')
var cipher = crypto.createCipher('aes-128-cbc','somepass')
var text = "uncle had a little farm"
var crypted = cipher.update(text,'utf8','hex')
crypted += cipher.final('hex')
//now crypted contains the hex representation of the ciphertext
et java
private static String decrypt(byte[] raw, byte[] encrypted) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, skeySpec );
byte[] decrypted = cipher.doFinal(encrypted);
return new String(decrypted);
}
la clé brute est créé comme ceci
private static byte[] getRawKey(String seed) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
byte[] seedBytes = seed.getBytes()
sr.setSeed(seedBytes);
kgen.init(128, sr); //192 and 256 bits may not be available
SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();
return raw;
}
tandis que le chiffré hex chaîne est convertie en octets comme ce
public static byte[] toByte(String hexString) {
int len = hexString.length()/2;
byte[] result = new byte[len];
for (int i = 0; i < len; i++)
result[i] = Integer.valueOf(hexString.substring(2*i, 2*i+2), 16).byteValue();
return result;
}
source d'informationauteur Shh | 2011-10-16
Vous devez vous connecter pour publier un commentaire.
Apparemment, si vous passez d'un mot de passe pour
crypto.createCipher()
il utilise OpenSSL estEVP_BytesToKey()
pour obtenir la clé. Vous pouvez passer soit une brute octets de la mémoire tampon et l'utiliser pour initialiser JavaSecretKey
ou imiter lesEVP_BytesToKey()
dans votre code Java. Utilisation$ man EVP_BytesToKey
pour plus de détails, mais, essentiellement, il hachages de la phrase plusieurs fois avec MD5 et concatène un sel.Comme pour l'utilisation d'une clé brute, quelque chose comme cela devrait vous permettre d'utiliser une clé brute:
var c = crypto.createCipheriv("aes-128-ecb", new Buffer("00010203050607080a0b0c0d0f101112", "hex").toString("binary"), "");
Noter que, puisque vous utilisez de la SRC, vous devez utiliser le même IV pour le chiffrement et le déchiffrement (vous pouvez l'ajouter à votre message, etc.)
Obligatoire avertissement: mise en œuvre d'un protocole cryptographique vous-même est rarement une bonne idée. Même si vous vous faites cela, vous allez utiliser la même clé pour tous les messages? Pour combien de temps? Si vous décidez de tourner la clé, comment vous gérer cela. Etc, .etc.
Merci à vous tous. vos réponses et commentaires m'a orienté dans la bonne direction, et avec un peu plus de recherche, j'ai réussi à obtenir un prototype fonctionnel (collé ci-dessous).
Il s'avère que le nœud de la crypto utilise MD5 de hachage de la clé, et le rembourrage est apparemment (obtenu avec essai et erreur) fait à l'aide de PKCS7Padding
Que pour les raisons de la faire, en premier lieu:
J'ai une application composée de trois parties:
A. d'un service principal
B. un tiers de banque de données
C. une application android en tant que client.
Le backend service prépare les données et les messages de la troisième partie.
L'application android obtient et/ou mises à jour des données dans la banque de données, le service peut agir.
La nécessité pour le chiffrement, est de garder les données confidentielles, même à partir d'un fournisseur tiers.
Comme pour la gestion des clés - je suppose que je peux demander au serveur de créer une nouvelle clé à chaque préconfiguré période de temps, les chiffrer avec la clé ancienne et de la poster sur le magasin de données pour le client de décrypter et de commencer à l'utiliser, mais c'est un peu overkill pour mes besoins.
Je peux aussi créer une paire de clés et l'utiliser pour transférer de la nouvelle clé symétrique à chaque fois dans un tout, mais c'est encore plus exagéré (pour ne pas mentionner le travail)
Anywho, voici le code:
Crypter sur Node.js
Déchiffrer sur Java:
L'exemple de la réponse à la question précédente n'a pas fonctionné pour moi lors de la tentative de Java SE depuis Java 7 se plaint que "l'AES/ECB/PKCS7Padding" ne peut pas être utilisé.
Toutefois, cela a fonctionné:
à chiffrer:
à déchiffrer:
Vous devez vous assurer que vous utilisez
sur les deux côtés de la connexion.
Pour la clésur le Java côté vous utilisez un certain travail pour dériver une clé à partir d'une chaîne - pas une telle chose est faite sur la node.js côté. Utiliser un algorithme de dérivation de clé ici (et le même sur les deux côtés).
Regardant à nouveau, la ligne
en effet, certains de dérivation de clé, juste le la documentation est le silence sur ce qu'il fait exactement:
Ok, ça au moins, dit la façon de coder, mais pas ce qui est fait ici. Donc, on peut utiliser l'autre méthode d'initialisation
crypto.createCipheriv
(qui prend la clé et le vecteur d'initialisation directement, et les utilise sans aucune modification), ou de chercher à la source.createCipher
sera en quelque sorte appeler la fonction C++ CipherInit dans node_crypto.cc. Il utilise dans l'essence de l'EVP_BytesToKey
de la fonction à dériver la clé à partir de la condition de chaîne de caractères (avec MD5, vide le sel et le comte 1), puis faites la même chose queCipherInitiv
(qui est appelée parcreateCipheriv
et utilise des IV et touche directement.)AES utilise 128 bits de la clé et de vecteur d'initialisation et MD5 a 128 bits de sortie, cela signifie en effet
(où + désigne la concaténation, pas plus). Vous pouvez ré-implémenter cette clé-dérivation en Java à l'aide de la MessageDigest classe, si nécessaire.
Une meilleure idée serait d'utiliser une certaine lenteur de dérivation de clé algorithme, spécialement si votre mot de passe est quelque chose de ce qu'un humain peut mémoriser. Ensuite, utilisez la pbkdf2 de fonction pour générer cette clé sur le node.js côté, et PBEKeySpec avec un SecretKeyFactory (avec l'algorithme de
PBKDF2WithHmacSHA1
) sur le Java côté. (Choisissez un nombre d'itérations qui ne vient pas de faire vos clients se plaignent de la lenteur sur la plupart des appareils courants.)Pour votre algorithme de chiffrementsur le Java côté vous dites "d'utiliser l'algorithme AES, quel que soit le mode de fonctionnement par défaut et le défaut mode de remplissage ici". Ne pas le faire, car il peut changer de fournisseur à fournisseur.
Au lieu de cela, utiliser des indications explicites du mode de fonctionnement (
CBC
dans votre cas), et la mention explicite de la mode de remplissage. Un exemple pourrait être:Ont un look à la node.js documentation pour voir comment indiquer un mode de remplissage (qui est la valeur par défaut, sélectionnez le même sur le Java côté). (À partir de la OpenSSL DG de la documentationil semble que la valeur par défaut est PKCS5Padding ici, trop.)
Aussi, au lieu de mettre en œuvre le cryptage de vous-même, pensez à utiliser TLS pour le chiffrement de transport. (Bien sûr, cela ne fonctionne que si vous avez une connexion en temps réel entre les deux côtés).