perl CBC DES相当于java

时间:2014-02-27 19:48:54

标签: java perl encryption passwords openssl

我们试图弄清楚如何在Java / scala中执行此操作:

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代码是我们无法改变的。 我在scala中尝试了一些东西,但是并没有真正做到这一点,例如:

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: [B@4896ceb3
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

我们最终需要做的是能够解密Perl设置的Java中的cookie。 非常感谢Java / scala中的任何帮助或指导

1 个答案:

答案 0 :(得分: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。