Linux上基于Java密码的加密失败

时间:2017-01-21 20:07:36

标签: java encryption

我需要帮助找出运行Linux Mint 17.2 Rafaela的机器上Java加密失败的原因。我的应用程序无法使用RC4算法解密以前加密的值。

我正在使用Java 8 u112进行测试,我安装了JCE,但这没有帮助。

以下是我创建的最小样本,适用于我的Windows机器:

import javax.xml.bind.DatatypeConverter;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;

public class CryptoTest
{

  private static final String ADMIN_PASSWORD = "admin";
  private static final String ADMIN_ENCRYPTED_PASSWORD = "532C05C5B5";                             // RC4 encrypted password using KEY
  private static final String ADMIN_AUTH_KEY = "1391a8a860b7d6e2e86df513700e490c16dae47cdae227ca"; // PBKDF2(username,password,salt)
  private static final String CRYPTO_ALGORITHM = "RC4";

  protected static String encryptPassword(String passwordDataToEncrypt, String userskey) throws Exception 
  {
    SecureRandom sr = new SecureRandom(userskey.getBytes());
    KeyGenerator kg = KeyGenerator.getInstance(CRYPTO_ALGORITHM);
    kg.init(sr);
    SecretKey sk = kg.generateKey();
    Cipher cipher = Cipher.getInstance(CRYPTO_ALGORITHM);
    cipher.init(Cipher.ENCRYPT_MODE, sk);
    return bytesToHex(cipher.doFinal(passwordDataToEncrypt.getBytes()));
  }

  private static String bytesToHex(byte[] in) 
  {
    return DatatypeConverter.printHexBinary(in);
  }

  private static byte[] hexStringToByteArray(String s) 
  {
    return DatatypeConverter.parseHexBinary(s);
  }

  protected static String decryptPassword(byte[] toDecryptPassword, String key) throws Exception 
  {
    SecureRandom sr = new SecureRandom(key.getBytes());
    KeyGenerator kg = KeyGenerator.getInstance(CRYPTO_ALGORITHM);
    kg.init(sr);
    SecretKey sk = kg.generateKey();
    Cipher cipher = Cipher.getInstance(CRYPTO_ALGORITHM);
    cipher.init(Cipher.DECRYPT_MODE, sk);
    return new String(cipher.doFinal(toDecryptPassword));
  }

  public static void assertEquals(String arg1, String arg2)
  {
    if (! arg1.equals(arg2))
    {
      System.out.println(String.format("%s does not equal %s", arg1, arg2));
    }
  }

  public static void testGetDecryptedPassword() throws Exception
  {
    String decryptedPassword = decryptPassword(hexStringToByteArray(ADMIN_ENCRYPTED_PASSWORD), ADMIN_AUTH_KEY);
    assertEquals(ADMIN_PASSWORD, decryptedPassword);
  }

  public static void testGetEncryptedPassword() throws Exception
  {
    String encryptedPassword = encryptPassword(ADMIN_PASSWORD, ADMIN_AUTH_KEY);
    assertEquals(ADMIN_ENCRYPTED_PASSWORD, encryptedPassword);
  }

  public static void testEncryptAndDecryptPasswords() throws Exception
  {
    String originalPassword = "password";
    String encryptedPassword = encryptPassword(originalPassword, ADMIN_AUTH_KEY);
    String decryptedPassword = decryptPassword(hexStringToByteArray(encryptedPassword), ADMIN_AUTH_KEY);
    assertEquals(originalPassword, decryptedPassword);

    originalPassword = "This is a STRONG password 4 me!!!@#$^";
    encryptedPassword = encryptPassword(originalPassword, ADMIN_AUTH_KEY);
    decryptedPassword = decryptPassword(hexStringToByteArray(encryptedPassword), ADMIN_AUTH_KEY);
    assertEquals(originalPassword, decryptedPassword);
  }

  public static void main(final String[] args)
  {
    try
    {
      int strength =  Cipher.getMaxAllowedKeyLength("AES");
      if ( strength > 128 ){
        System.out.printf("isUnlimitedSupported=TRUE,strength: %d%n",strength);
      } else {
        System.out.printf("isUnlimitedSupported=FALSE,strength: %d%n",strength);
      }

      testGetDecryptedPassword();
      testGetEncryptedPassword();
      testEncryptAndDecryptPasswords();
    }
    catch (Exception e)
    {
      System.out.printf("Caught exception: %s\n", e.getMessage());
      e.printStackTrace(System.out);
    }
  }
}

我的linux框上的输出是:

isUnlimitedSupported=TRUE,strength: 2147483647
admin does not equal <junk>
532C05C5B5 does not equal 5D16D89D2F
password does not equal <junk>
This is a STRONG password 4 me!!!@#$^ does not equal <junk>

<junk>是一堆不可打印的字符。

1 个答案:

答案 0 :(得分:2)

您的代码假定您每次使用以下代码中的相同密码初始化SecretKey时都会获得相同的SecureRandom()

SecureRandom sr = new SecureRandom(userskey.getBytes());
KeyGenerator kg = KeyGenerator.getInstance(CRYPTO_ALGORITHM);
kg.init(sr);
SecretKey sk = kg.generateKey();

你真的不能做出这样的假设,你不应该使用这种方法。 SecureRandom JCA 体系结构的一部分,实例化新SecureRandom(..)时获得的实际实现取决于系统上可用的安全提供程序,以及每个安全提供程序的优先级提供者有。

如果您需要使用密码创建加密密钥,则应使用为PBKDF2创建的密钥派生函数。