将String加密从Ruby迁移到Java

时间:2017-02-22 23:35:19

标签: java ruby encryption des

我需要在Java中生成与使用Ruby encrypted_strings库构建的加密字符串相同的加密字符串。我尝试了很多不同的方法,但我的Java代码不断返回不同的输出,我无法理解我做错了什么。

下面是ruby脚本,它产生了我无法用Java获得的所需输出。

#!/usr/bin/ruby
require 'encrypted_strings'

data = 'Whackabad'
password = 'bAJLyifeUJUBFWdHzVbykfDmPHtLKLMzViHW9aHGmyTLD8hGYZ'

encrypted_data = data.encrypt(:symmetric, :password => password)
printf "Data: #{data}\n"
printf "Encrypted Data: #{encrypted_data}"

输出:

Data: Whackabad
Encrypted Data: AEsDXVcgh2jsTjlDgh+REg==

我查看了该库,它似乎使用DES-EDE3-CBC作为加密的默认算法。我从这里推断出我应该使用DESedeTripleDES算法和CBC模式。作为填充选项,我使用PKCS5Padding因为库正在调用pkcs5_keyivgen

以下是试图重现相同输出失败的Java代码。

package ...

import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.IvParameterSpec;

public class SymmetricDESedeCipher {
    private static final String DATA = "Whackabad";
    private static final String key = "bAJLyifeUJUBFWdHzVbykfDmPHtLKLMzViHW9aHGmyTLD8hGYZ";
    private static final String ALGORITHM = "DESede";
    private static final String XFORM = "DESede/CBC/PKCS5Padding";

    private static byte[] iv = new byte[8];

    private static byte[] encrypt(byte[] inpBytes,
                                  SecretKey key, String XFORM) throws Exception {
        Cipher cipher = Cipher.getInstance(XFORM);
        IvParameterSpec ips = new IvParameterSpec(iv);
        cipher.init(Cipher.ENCRYPT_MODE, key, ips);
        return cipher.doFinal(inpBytes);
    }

    public static void main(String[] unused) throws Exception {
        byte[] keyBytes = key.getBytes();
        DESedeKeySpec desKeySpec = new DESedeKeySpec(keyBytes);
        SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(ALGORITHM);

        SecretKey secretKey = secretKeyFactory.generateSecret(desKeySpec);

        byte[] dataBytes = DATA.getBytes();
        byte[] encBytes = encrypt(dataBytes, secretKey, XFORM);

        System.out.println("Data: " + DATA);
        System.out.println("Encrypted Data: " + new BASE64Encoder().encode(encBytes));
    }
}

输出

Data: Whackabad
Encrypted Data: ScPTKQBsR9Ni1nJ1tsMaaQ==

我见过有人加密来自Java的数据要从Ruby解密,反之亦然,使用不同的算法,所以我认为这可以实现,但我看不出有什么问题。你有好主意吗?如果是这样,那会有很大的帮助!

谢谢

1 个答案:

答案 0 :(得分:1)

首先要做的是从给定的密码derive the IV and key开始。

从上面的链接中,您将获得分别与"VDiJjncs4ak=""s9e42J3PpmQv8n5T8L3zzuFaGdrzK/wU"对应的编码IV和KEY。 这意味着Java代码中使用的密钥和IV向量是错误的,如评论中所述。

以下是生成的Java代码:

public class SymmetricDESedeCipher {
    private static final String DATA = "Whackabad";
    private static final String ALGORITHM = "DESede";
    private static final String XFORM = "DESede/CBC/PKCS5Padding";
    private static final String KEY = "s9e42J3PpmQv8n5T8L3zzuFaGdrzK/wU";
    private static final String IV = "VDiJjncs4ak=";

    private static byte[] encrypt(String data,
                                  SecretKey key, String XFORM, byte[] iv) throws Exception {
        Cipher cipher = Cipher.getInstance(XFORM);
        cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
        return cipher.doFinal(data.getBytes());
    }

    public static void main(String[] unused) throws Exception {
        DESedeKeySpec spec = new DESedeKeySpec(new BASE64Decoder().decodeBuffer(KEY));
        SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(ALGORITHM);
        SecretKey secretKey = secretKeyFactory.generateSecret(spec);

        byte[] encBytes = encrypt(DATA, secretKey, XFORM,  new BASE64Decoder().decodeBuffer(IV));

        System.out.println("Data: " + DATA);
        System.out.println("Encrypted Data: " + new BASE64Encoder().encode(encBytes));
    }
}

输出:

Data: Whackabad
Encrypted Data: AEsDXVcgh2jsTjlDgh+REg==