2014-02-27 35 views
2

我们试图找出如何在Java/Scala中做到这一点:perl的CBC DES等同于Java的

use Crypt::CBC; 
$aesKey   = "some key" 
$cipher = new Crypt::CBC($aesKey, "DES"); 
$encrypted = $cipher->encrypt("hello world"); 
print $encrypted // prints: Salted__�,%�8XL�/1�&�n;����쀍c 
print encode_base64($encrypted); // prints: U2FsdGVkX19JwL/Dc4gwehTfZ1ahNlO6Jf41vALcshg= 
$decrypted = $cipher->decrypt($encrypted); 
print $decrypted // prints: hello world 

的问题是,Perl代码是我们不能chanage。 我尝试了一些东西,斯卡拉但并没有真正得到它的权利,例如像这样:

val secretKey = new SecretKeySpec("some key".getBytes("UTF-8"), "DES") 
val encipher = Cipher.getInstance("DES/CBC/PKCS5Padding"); 
encipher.init(Cipher.ENCRYPT_MODE, secretKey) 
val encrypted = encipher.doFinal("hello world".getBytes) 
println(encrypted) // prints: [[email protected] 
println(java.util.Arrays.toString(encrypted)) // [-45, -126, -90, 36, 8, -73, 6, 85, -94, 108, 100, -120, 15, -8, 126, 76] 
println(Hex.encodeHexString(encrypted)) //prints: 822c90f1116686e75160ff06c8faf4a4 

我们最终需要做的是能够解密在Java中的cookie被Perl设置。 用Java/Scala的任何帮助或方向将非常理解

+1

由于加密结果不是有效的文本编码,因此可能会打印输出中的“ ”字符。相反,base-64编码“$ encrypted”并打印。这会让我们更容易理解,因为我们会得到实际的结果进行比较,而不是其中的片段。 – erickson

+0

感谢您的建议@erickson,我更新了perl和java的代码 – Dahdahm

+0

这很让人困惑。你在PERL中使用UTF-8吗?我假设你需要“US-ASCII”(或其他编码)。另外,你应该使用'println(java.util.Arrays.toString(encrypted))' –

回答

3
import java.nio.charset.StandardCharsets; 
import java.security.GeneralSecurityException; 
import java.security.MessageDigest; 
import java.security.SecureRandom; 
import java.security.spec.AlgorithmParameterSpec; 
import java.util.Arrays; 

import javax.crypto.Cipher; 
import javax.crypto.SecretKey; 
import javax.crypto.spec.IvParameterSpec; 
import javax.crypto.spec.SecretKeySpec; 

final class CrapEncryption 
{ 

    private static final byte[] MAGIC = "Salted__".getBytes(StandardCharsets.US_ASCII); 

    private static final int KEY_LEN = 8; 

    private static final int SALT_LEN = 8; 

    private static final SecureRandom random = new SecureRandom(); 

    static byte[] pretendToEncrypt(byte[] password, byte[] msg) 
    throws GeneralSecurityException 
    { 
    byte[] salt = new byte[SALT_LEN]; 
    random.nextBytes(salt); 
    MessageDigest md5 = MessageDigest.getInstance("MD5"); 
    md5.update(password); 
    md5.update(salt); 
    byte[] dk = md5.digest(); 
    Cipher des; 
    try { 
     SecretKey key = new SecretKeySpec(dk, 0, KEY_LEN, "DES"); 
     AlgorithmParameterSpec iv = new IvParameterSpec(dk, KEY_LEN, SALT_LEN); 
     des = Cipher.getInstance("DES/CBC/PKCS5Padding"); 
     des.init(Cipher.ENCRYPT_MODE, key, iv); 
    } 
    finally { 
     Arrays.fill(dk, (byte) 0); 
    } 
    byte[] pkg = new byte[des.getOutputSize(msg.length) + MAGIC.length + SALT_LEN]; 
    System.arraycopy(MAGIC, 0, pkg, 0, MAGIC.length); 
    System.arraycopy(salt, 0, pkg, MAGIC.length, SALT_LEN); 
    des.doFinal(msg, 0, msg.length, pkg, MAGIC.length + SALT_LEN); 
    return pkg; 
    } 

    static byte[] decrypt(byte[] password, byte[] pkg) 
    throws GeneralSecurityException 
    { 
    if ((pkg.length < MAGIC.length) || !Arrays.equals(Arrays.copyOfRange(pkg, 0, MAGIC.length), MAGIC)) 
     throw new IllegalArgumentException("Expected magic number \"Salted__\""); 
    if (pkg.length < MAGIC.length + SALT_LEN) 
     throw new IllegalArgumentException("Missing salt"); 
    MessageDigest md5 = MessageDigest.getInstance("MD5"); 
    md5.update(password); /* password */ 
    md5.update(pkg, MAGIC.length, SALT_LEN); /* salt */ 
    byte[] dk = md5.digest(); 
    Cipher des; 
    try { 
     SecretKey secret = new SecretKeySpec(dk, 0, KEY_LEN, "DES"); 
     des = Cipher.getInstance("DES/CBC/PKCS5Padding"); 
     des.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(dk, KEY_LEN, SALT_LEN)); 
    } 
    finally { 
     Arrays.fill(dk, (byte) 0); 
    } 
    return des.doFinal(pkg, MAGIC.length + SALT_LEN, pkg.length - MAGIC.length - SALT_LEN); 
    } 

    public static void main(String... argv) 
    throws Exception 
    { 
    byte[] password = "some key".getBytes(StandardCharsets.UTF_8); 
    byte[] message = "hello world".getBytes(StandardCharsets.UTF_8); 
    byte[] encrypted = pretendToEncrypt(password, message); 
    byte[] recovered = decrypt(password, encrypted); 
    System.out.println(new String(recovered, StandardCharsets.UTF_8)); 
    } 

} 

为什么"CrapEncryption""pretendToEncrypt"?因为这里使用的算法是最糟糕的 DES不安全。 MD5不安全。密钥派生函数只使用一次迭代。这全是垃圾。改用AES和PBKDF2。

+0

:)谢谢! 这个完美的作品。 我必须将它转换为scala,并且必须将来自perl的cookie解码为Perl CBC默认的ISO_8859_1。 也感谢您指出加密是多么糟糕,绝对同意。我们正在扩展一个大型机应用程序,如上所述(perl)对cookie进行加密,我们预计会在scala中读取cookie以匹配用户会话。 然而,我会推动其他团队(perl)根据您的建议更改cookie加密。再一次,非常感谢! – Dahdahm