13

私はJavaで暗号化コードを持っています。暗号化部分をノードに移植しようとしています。基本的に、node が crypto モジュールを使用して暗号化を行い、次に Java が復号化を行います。

Javaで暗号化を行う方法は次のとおりです。

protected static String encrypt(String plaintext) {
    final byte[] KEY = {
            0x6d, 0x79, 0x56, 0x65, 0x72, 0x79, 0x54, 0x6f, 0x70,
            0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4b
    };

    try {
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        final SecretKeySpec secretKey = new SecretKeySpec(KEY, "AES");
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        final String encryptedString = Base64.encodeToString(
            cipher.doFinal(plaintext.getBytes()), Base64.DEFAULT);

        return encryptedString;
    } catch (Exception e) {
        return null;
    }
}

ノードで暗号化を行う方法は次のとおりです。

var crypto = require('crypto'),
    key = new Buffer('6d7956657279546f705365637265744b', 'hex'),
    cipher = crypto.createCipher('aes-128-ecb', key),
    chunks = [];

cipher.setAutoPadding(true);
chunks.push(cipher.update(
    new Buffer(JSON.stringify({someKey: "someValue"}), 'utf8'),
    null, 'base64'));
chunks.push(cipher.final('base64'));

var encryptedString = chunks.join('');

Java では、string を取得しますT4RlJo5ENV8h1uvmOHzz1KjyXzBoBuqVLSTHsPppljA=。これは正しく復号化されます。ただし、ノードでal084hEpTK7gOYGQRSGxF+WWKvNYhT4SC7MukrzHieM=は、明らかに異なるものを取得するため、正しく復号化されません。

私と同じ問題を抱えている人を探してみましたが、このgithub の問題は私が見つけることができる最も近いものです。その問題で示唆されているように、openssl を次のように実行してみました。

$ echo -e '{"someKey": "someValue"}' | openssl enc -a -e -aes-128-ecb -K "6d7956657279546f705365637265744b"
T4RlJo5ENV8h1uvmOHzz1MY2bhoFRHZ+ClxsV24l2BU=

私が得た結果は、Javaによって生成されたものに十分近いものでしたが、それでも異なっていました:

T4RlJo5ENV8h1uvmOHzz1MY2bhoFRHZ+ClxsV24l2BU=  // openssl
T4RlJo5ENV8h1uvmOHzz1KjyXzBoBuqVLSTHsPppljA=  // java
al084hEpTK7gOYGQRSGxF+WWKvNYhT4SC7MukrzHieM=  // node

これにより、ノードが Java コードと同じ暗号化された文字列を出力するようにするにはどうすればよいでしょうか? コードをノードでのみ変更できますが、Java では変更できません。

4

4 に答える 4

12

ノード側と Java 側の両方から完全な CBC の例を投稿したと思います (128 ではなく 256): java.security.InvalidKeyException が発生した場合は、Java Cryptography Extension (JCE) の無制限強度の管轄ポリシー ファイルをインストールする必要があります。

Java 6 リンク Java 7 リンク Java 8 リンク

Java の暗号化と復号化。

    import java.security.MessageDigest;
    import javax.crypto.spec.SecretKeySpec;
    import javax.crypto.spec.IvParameterSpec;
    import javax.crypto.Cipher;
    import java.util.Base64;
    import javax.xml.bind.DatatypeConverter;

    public class AESExample {
        private static byte[] iv = "0000000000000000".getBytes();
        private static String decrypt(String encrypted, String seed)
                throws Exception {
            byte[] keyb = seed.getBytes("utf-8");
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            byte[] thedigest = md.digest(keyb);
            SecretKeySpec skey = new SecretKeySpec(thedigest, "AES");
            Cipher dcipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            dcipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(seed.getBytes("UTF-8"), "AES"), new IvParameterSpec(iv));
            byte[] clearbyte = dcipher.doFinal(DatatypeConverter
                    .parseHexBinary(encrypted));
            return new String(clearbyte);
        }
        public static String encrypt(String content, String key) throws Exception {
            byte[] input = content.getBytes("utf-8");
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            byte[] thedigest = md.digest(key.getBytes("utf-8"));
            SecretKeySpec skc = new SecretKeySpec(thedigest, "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key.getBytes("UTF-8"), "AES"), new IvParameterSpec(iv));
            byte[] cipherText = new byte[cipher.getOutputSize(input.length)];
            int ctLength = cipher.update(input, 0, input.length, cipherText, 0);
            ctLength += cipher.doFinal(cipherText, ctLength);
            return DatatypeConverter.printHexBinary(cipherText);
        }

public static String encrypt128(String content, String key) throws Exception {
        byte[] input = content.getBytes("utf-8");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(DatatypeConverter.parseHexBinary(key), "AES"), new IvParameterSpec(iv));
         byte[] encrypted = cipher.doFinal(content.getBytes("UTF-8"));
        return DatatypeConverter.printHexBinary(encrypted);
    }

        public static void main(String[] args) throws Exception {
            String data = "Here is my string";
            String key = "1234567891123456";
            String cipher = AESExample.encrypt(data, key);
            String decipher = AESExample.decrypt(cipher, key);
            System.out.println(cipher);
            System.out.println(decipher);
            System.out.println(AESExample.encrypt(data, "1234567891123456"));
            System.out.println(AESExample.encrypt128(data, "d7900701209d3fbac4e214dfeb5f230f"));
        }
    }

以下の両方向のノード:

    var crypto = require('crypto');
        var iv = new Buffer('0000000000000000');
        // reference to converting between buffers http://nodejs.org/api/buffer.html#buffer_new_buffer_str_encoding
        // reference node crypto api http://nodejs.org/api/crypto.html#crypto_crypto_createcipheriv_algorithm_key_iv
        // reference to ECB vs CBC cipher methods http://crypto.stackexchange.com/questions/225/should-i-use-ecb-or-cbc-encryption-mode-for-my-block-cipher

        var encrypt = function(data, key) {
          var decodeKey = crypto.createHash('sha256').update(key, 'utf-8').digest();
          var cipher = crypto.createCipheriv('aes-256-cbc', decodeKey, iv);
          return cipher.update(data, 'utf8', 'hex') + cipher.final('hex');
        };

        var decrypt = function(data, key) {
          var encodeKey = crypto.createHash('sha256').update(key, 'utf-8').digest();
          var cipher = crypto.createDecipheriv('aes-256-cbc', encodeKey, iv);
          return cipher.update(data, 'hex', 'utf8') + cipher.final('utf8');
        };

       var decrypt128 = function(data, key) {

          var encodeKey = crypto.createHash('sha256').update(key, 'utf-8').digest();
         var cipher = crypto.createDecipheriv('aes-128-cbc', new Buffer(key, 'hex'),
    new Buffer(
      iv));
  return cipher.update(data, 'hex', 'utf8') + cipher.final('utf8');
};
        var data = 'Here is my string'
        var key = '1234567891123456';
        var cipher = encrypt(data, key);
        var decipher = decrypt(cipher, key);
        console.log(cipher);
        console.log(decipher);
        // the string below was generated from the "main" in the java side
        console.log(decrypt(
          "79D78BEFC06827B118A2ABC6BD9D544E83F92930144432F22A6909EF18E0FDD1", key));
        console.log(decrypt128(
  "3EB7CF373E108ACA93E85D170C000938A6B3DCCED53A4BFC0F5A18B7DDC02499",
  "d7900701209d3fbac4e214dfeb5f230f"));
于 2015-01-05T16:10:29.913 に答える
10

最後に、私の問題の解決策を見つけました。この男のおかげです。解決策の鍵は、初期化ベクトルです。要旨を引用:

// ECB モードは IV を必要としないため、このままにしておくとうまく機能します。

ソリューションは次のようになります。

var crypto = require('crypto'),
    iv = new Buffer(''),
    key = new Buffer('6d7956657279546f705365637265744b', 'hex'),
    cipher = cypto.createCipheriv('aes-128-ecb', key, iv),
    chunks = [];

chunks.push(cipher.update(
    new Buffer(JSON.stringify({someKey: "someValue"}), 'utf8'),
    'buffer', 'base64'));
chunks.push(cipher.final('base64'));
var encryptedString = chunks.join('');
于 2013-10-31T07:04:02.253 に答える
5

Node.Js での暗号化と Java での復号化の実例:

暗号化するには:

var crypto = require('crypto')
var cipher = crypto.createCipher('aes-128-ecb','somepassword')
var text = "the big brown fox jumped over the fence"
var crypted = cipher.update(text,'utf-8','hex')
crypted += cipher.final('hex')
//now crypted contains the hex representation of the ciphertext

解読するには:

private static String decrypt(String seed, String encrypted) throws Exception {
    byte[] keyb = seed.getBytes("UTF-8");
    MessageDigest md = MessageDigest.getInstance("MD5");
    byte[] thedigest = md.digest(keyb);
    SecretKeySpec skey = new SecretKeySpec(thedigest, "AES");
    Cipher dcipher = Cipher.getInstance("AES");
    dcipher.init(Cipher.DECRYPT_MODE, skey);

    byte[] clearbyte = dcipher.doFinal(toByte(encrypted));
    return new String(clearbyte);
}

private 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;
}
于 2014-01-21T08:42:54.330 に答える