2014-02-27 34 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