1

首先我想说声谢谢...

我写了一个程序,它用 Enum 进行加密和解密。枚举有 AES、BlowFish、DESede。我的程序将支持这 3 种加密算法。

然后我想用 SecretKeyFactory 生成一个 SecretKey。但我想,我生成一个密钥是错误的。(显然我在代码中放松了自己。我不知道我能做什么......)

我的代码如下。该计划的目的是

  • 用户将编写加密和解密方法参数。(文本,加密算法)
  • 算法类型将在 Enum 类型中选择。(枚举有3种算法格式)
  • 根据输入的加密类型,程序将对输入的文本进行加密。

我知道我的代码真的很糟糕。它有很多不必要的声明和逻辑错误。

代码有时运行良好,有时会崩溃。

编辑 =问题是我的代码并不总是有效。有时会出错。错误是 = javax.crypto.BadPaddingException:给定最终块未正确填充

谢谢你的回答

import java.security.SecureRandom;
import java.security.spec.KeySpec;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

public class SymetricAlgorithms {

    private static enum algorithms { //Enum declaration 3 encryption types here

        AES, BlowFish, DESede;

    }

    private static String data = "HOWCANISOLVETHIS"; //this will be encrypt and decrypt

    public static void main(String[] args) throws Throwable {

        SecretKey kgen = GenerateKey(); // Create a key.
        String encrypText = encrypt(kgen, data, algorithms.AES); //encrypt method calling here.
        String decrypText = dencypt(kgen, encrypText, algorithms.AES);//decrypt method calling here.
        System.out.println("plaintext = " + data + " key = " + kgen
                + "\nEncryptedText = " + encrypText
                + "\nDecryptedText = " + decrypText);

    }

    public static String dencypt(SecretKey inKey, String text, algorithms eValue)throws Throwable {//decryption
        try {
            byte[] text2 = text.getBytes(); //convert from parameters TEXT to Bytes
            Cipher cipher = Cipher.getInstance("AES"); //Cipher initialize and choose encryption method (AES)
            cipher.init(Cipher.DECRYPT_MODE, inKey); //cipher process
            byte plainTextByte[] = new byte[20]; //Creating byte array
            plainTextByte =cipher.doFinal(text2);//using byte array to assign ciphers result
            System.out.println(plainTextByte);
            return new String(plainTextByte);
        } catch (Exception e) {
            System.err.println("Data Cant Decrypted !");
            e.printStackTrace();
        }
        return null;


    }

    public static String encrypt(SecretKey inKey, String text, algorithms eValue)
            throws Throwable {
        try {
            Cipher cipher = null; //cipher declaration
            switch (eValue) {//Enum. 3 types here and control structure for Users choosing encryption type is acceptable
            case AES:cipher = Cipher.getInstance("AES");
                break;
            case BlowFish:Cipher cipher2 = Cipher.getInstance("BlowFish");
            cipher = cipher2;
                break;
            case DESede:Cipher cipher3 = Cipher.getInstance("DESede");
            cipher=cipher3;
                break;
            default:
                System.out.println("Unexpectable value input.");
                break;

            }
            System.out.println(inKey);
            //Cipher cipher = Cipher.getInstance("AES");
            cipher.init(Cipher.ENCRYPT_MODE, inKey);
            byte[] ciphertext = cipher.doFinal(text.getBytes("UTF-8"));//cipher result is assign to byte array
            System.out.println(ciphertext);
            return new String(ciphertext);
        } catch (Exception e) {
            System.err.println("Unexpectable algorithm type !");
            e.printStackTrace();
        }
        return null;

    }

    public static SecretKey GenerateKey() throws Throwable {//Generate a key for using crypt
            //could sb explain these? =D I loose myself. I combined codes from finding internet...Failed...    
        try {
            SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
            SecureRandom prng = SecureRandom.getInstance("SHA1PRNG");
            byte bytes[] = new byte[20];
            prng.nextBytes(bytes);
            String passwordTemp = prng.toString();
            String saltTemp = passwordTemp;
            char[] password = passwordTemp.toCharArray();
            byte[] salt = saltTemp.getBytes();
            KeySpec spec = new PBEKeySpec(password, salt, 65536, 128);
            SecretKey tmp = factory.generateSecret(spec);
            SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
            return secret;
        } catch (Exception e) {
            System.err.println("Key cant be generated !");
            e.printStackTrace();
        }
        return null;

    }

}
4

1 回答 1

4

问题的主题是对字符串和字节之间关系的误解。在 encrypt 方法的最后,你认为这两行是做什么的:

byte[] ciphertext = cipher.doFinal(...
return new String(ciphertext);

最后一行采用几乎可以是任何内容的加密字节,并尝试将这些字节解释为对字符串的某些字符进行编码。使用什么编码?不带字符编码参数的字符串构造函数使用系统默认编码,这取决于 JVM/OS/Locale。可以说它是UTF-8。您是否保证加密字节实际上会有一些字符?答案:没有。当您获取结果字符串并调用 .getBytes("UTF-8") 时,您会得到相同的字节吗?答:不,有多个字节序列编码相同的字符,因此不能保证 new String(bytes, "UTF-8").getBytes("UTF-8") 返回您开始使用的字节。

总之,不要试图将任意字节解释为字符串。让你的 encrypt 方法返回 byte[],而你的 decryp 方法需要一个字节数组来解码——然后它就可以工作了。

没有必要让您的程序工作,但如果您必须将加密字节表示为字符串,请考虑 base64 编码或十六进制编码——这些编码将每个可能的字节(或字节序列)唯一地映射到字符串。

更新:这是一个更简洁的 generateKey() 方法。它允许您将密码作为参数传递。

public static SecretKey generateKey(String password) {
    try {
        SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
        byte saltBytes[] = new byte[20];
        secureRandom.nextBytes(saltBytes);

        KeySpec spec = new PBEKeySpec(password.toCharArray(), saltBytes, 65536, 128);
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        SecretKey secretKey = factory.generateSecret(spec);

        return new SecretKeySpec(secretKey.getEncoded(), "AES");
    } catch (Exception e) {
        throw new IllegalStateException("Key cant be generated !");
    }
}
于 2013-07-04T15:38:44.823 回答