如何将String转换为SecretKey

时间:2010-12-29 03:28:54

标签: java encryption

我想将String转换为secretKey

public void generateCode(String keyStr){ 
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128); // 192 and 256 bits may not be available
// Generate the secret key specs.
secretKey skey=keyStr;  //How can I make the casting here
//SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();
}

我尝试使用BASE64Decoder而不是secretKey,但我遇到的问题是我无法指定密钥长度。

修改 我想从其他地方调用此函数

 static public String encrypt(String message , String key , int keyLength) throws Exception {
     // Get the KeyGenerator
   KeyGenerator kgen = KeyGenerator.getInstance("AES");
    kgen.init(keyLength); // 192 and 256 bits may not be available
    // Generate the secret key specs.
     SecretKey skey = key; //here is the error
   byte[] raw = skey.getEncoded();
    SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
    // Instantiate the cipher
    Cipher cipher = Cipher.getInstance("AES");

    cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
    System.out.println("msg is" + message + "\n raw is" + raw);
    byte[] encrypted = cipher.doFinal(message.getBytes());
    String cryptedValue = new String(encrypted);
    System.out.println("encrypted string: " + cryptedValue);
    return cryptedValue;
}

如果有人可以提供帮助,我会非常感激。

2 个答案:

答案 0 :(得分:37)

由于这些特殊原因,没有完整性检查

  1. 用例并不明显。
  2. "AES/GCM/NoPadding"模式仅适用于Java 7以后的
  3. 取决于用户是否要部署,例如HMAC和/或AESCMAC(推荐)。
  4. 至少需要额外的钥匙,并且需要两次完整的通行证。
  5. 如果您在双方都实施了GCM模式 - 例如在Java 6上使用Bouncy Castle - 请继续使用它,因为它更加安全(只要“IV”非常独特)。改变实施应该很容易。

    有关加密的实施说明

    1. 当在无限制的客户端/服务器角色中使用时,由于填充oracle攻击(它们每字节需要128次尝试或更低,平均而言,与算法或密钥大小无关),因此该实现不安全。您需要在加密数据上使用MAC,HMAC或签名,并在解密之前对其进行验证,以便在客户端/服务器模式下进行部署。
    2. 如果解密失败,
    3. Decrypt将返回null。这只能指示一个填充异常,应该对其进行充分处理(我是否警告填充oracle攻击?)
    4. 无效密钥将以InvalidArgumentException返回。
    5. 所有其他与安全性相关的异常都“在表下扫描”,因为这意味着Java运行时环境无效。例如,对于每个Java SE实现,支持"UTF-8""AES/CBC/PKCS5Padding" 必需
    6. 其他一些注释

      1. 请不要尝试相反的方法并将字节直接插入到加密方法的输入字符串中(例如,使用new String(byte[]))。该方法可能会无声地失败!
      2. 针对可读性进行了优化。如果您更喜欢速度和更好的内存占用,请选择Base64流和CipherStream实现。
      3. 您至少需要Java 6 SE或兼容才能运行此代码。
      4. 对于超过128位的AES密钥大小,加密/解密可能失败,因为可能需要用于无限制加密的策略文件(可从Oracle获得)
      5. 出口加密时要小心政府规定。
      6. 此实现使用十六进制键而不是base64键,因为它们足够小,十六进制更容易手动编辑/验证。
      7. 使用从JDK检索到的hex和base64编码/解码,无需任何外部库。
      8. 优步易于使用,但当然不是非常面向对象,没有加密/解密中使用的对象实例的缓存。随意重构。
      9. 好的,这里有一些代码......

            public static String encrypt(final String plainMessage,
                    final String symKeyHex) {
                final byte[] symKeyData = DatatypeConverter.parseHexBinary(symKeyHex);
        
                final byte[] encodedMessage = plainMessage.getBytes(Charset
                        .forName("UTF-8"));
                try {
                    final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
                    final int blockSize = cipher.getBlockSize();
        
                    // create the key
                    final SecretKeySpec symKey = new SecretKeySpec(symKeyData, "AES");
        
                    // generate random IV using block size (possibly create a method for
                    // this)
                    final byte[] ivData = new byte[blockSize];
                    final SecureRandom rnd = SecureRandom.getInstance("SHA1PRNG");
                    rnd.nextBytes(ivData);
                    final IvParameterSpec iv = new IvParameterSpec(ivData);
        
                    cipher.init(Cipher.ENCRYPT_MODE, symKey, iv);
        
                    final byte[] encryptedMessage = cipher.doFinal(encodedMessage);
        
                    // concatenate IV and encrypted message
                    final byte[] ivAndEncryptedMessage = new byte[ivData.length
                            + encryptedMessage.length];
                    System.arraycopy(ivData, 0, ivAndEncryptedMessage, 0, blockSize);
                    System.arraycopy(encryptedMessage, 0, ivAndEncryptedMessage,
                            blockSize, encryptedMessage.length);
        
                    final String ivAndEncryptedMessageBase64 = DatatypeConverter
                            .printBase64Binary(ivAndEncryptedMessage);
        
                    return ivAndEncryptedMessageBase64;
                } catch (InvalidKeyException e) {
                    throw new IllegalArgumentException(
                            "key argument does not contain a valid AES key");
                } catch (GeneralSecurityException e) {
                    throw new IllegalStateException(
                            "Unexpected exception during encryption", e);
                }
            }
        
            public static String decrypt(final String ivAndEncryptedMessageBase64,
                    final String symKeyHex) {
                final byte[] symKeyData = DatatypeConverter.parseHexBinary(symKeyHex);
        
                final byte[] ivAndEncryptedMessage = DatatypeConverter
                        .parseBase64Binary(ivAndEncryptedMessageBase64);
                try {
                    final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
                    final int blockSize = cipher.getBlockSize();
        
                    // create the key
                    final SecretKeySpec symKey = new SecretKeySpec(symKeyData, "AES");
        
                    // retrieve random IV from start of the received message
                    final byte[] ivData = new byte[blockSize];
                    System.arraycopy(ivAndEncryptedMessage, 0, ivData, 0, blockSize);
                    final IvParameterSpec iv = new IvParameterSpec(ivData);
        
                    // retrieve the encrypted message itself
                    final byte[] encryptedMessage = new byte[ivAndEncryptedMessage.length
                            - blockSize];
                    System.arraycopy(ivAndEncryptedMessage, blockSize,
                            encryptedMessage, 0, encryptedMessage.length);
        
                    cipher.init(Cipher.DECRYPT_MODE, symKey, iv);
        
                    final byte[] encodedMessage = cipher.doFinal(encryptedMessage);
        
                    // concatenate IV and encrypted message
                    final String message = new String(encodedMessage,
                            Charset.forName("UTF-8"));
        
                    return message;
                } catch (InvalidKeyException e) {
                    throw new IllegalArgumentException(
                            "key argument does not contain a valid AES key");
                } catch (BadPaddingException e) {
                    // you'd better know about padding oracle attacks
                    return null;
                } catch (GeneralSecurityException e) {
                    throw new IllegalStateException(
                            "Unexpected exception during decryption", e);
                }
            }
        

        用法:

            String plain = "Zaphod's just zis guy, ya knöw?";
            String encrypted = encrypt(plain, "000102030405060708090A0B0C0D0E0F");
            System.out.println(encrypted);
            String decrypted = decrypt(encrypted, "000102030405060708090A0B0C0D0E0F");
            if (decrypted != null && decrypted.equals(plain)) {
                System.out.println("Hey! " + decrypted);
            } else {
                System.out.println("Bummer!");
            }
        

答案 1 :(得分:3)

这里是使用Base64 Util类而不是DatatypeConverter

的版本
public static String encrypt(final String plainMessage,
                             final String symKeyHex) {
    final byte[] symKeyData = Base64.decode(symKeyHex,Base64.DEFAULT);

    final byte[] encodedMessage = plainMessage.getBytes(Charset
            .forName("UTF-8"));
    try {
        final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        final int blockSize = cipher.getBlockSize();

        // create the key
        final SecretKeySpec symKey = new SecretKeySpec(symKeyData, "AES");

        // generate random IV using block size (possibly create a method for
        // this)
        final byte[] ivData = new byte[blockSize];
        final SecureRandom rnd = SecureRandom.getInstance("SHA1PRNG");
        rnd.nextBytes(ivData);
        final IvParameterSpec iv = new IvParameterSpec(ivData);

        cipher.init(Cipher.ENCRYPT_MODE, symKey, iv);

        final byte[] encryptedMessage = cipher.doFinal(encodedMessage);

        // concatenate IV and encrypted message
        final byte[] ivAndEncryptedMessage = new byte[ivData.length
                + encryptedMessage.length];
        System.arraycopy(ivData, 0, ivAndEncryptedMessage, 0, blockSize);
        System.arraycopy(encryptedMessage, 0, ivAndEncryptedMessage,
                blockSize, encryptedMessage.length);

        final String ivAndEncryptedMessageBase64 = Base64.encodeToString(ivAndEncryptedMessage,Base64.DEFAULT);

        return ivAndEncryptedMessageBase64;
    } catch (InvalidKeyException e) {
        throw new IllegalArgumentException(
                "key argument does not contain a valid AES key");
    } catch (GeneralSecurityException e) {
        throw new IllegalStateException(
                "Unexpected exception during encryption", e);
    }
}

public static String decrypt(final String ivAndEncryptedMessageBase64,
                             final String symKeyHex) {
    final byte[] symKeyData = Base64.decode((symKeyHex),Base64.DEFAULT);

    final byte[] ivAndEncryptedMessage = Base64.decode(ivAndEncryptedMessageBase64,Base64.DEFAULT);
    try {
        final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        final int blockSize = cipher.getBlockSize();

        // create the key
        final SecretKeySpec symKey = new SecretKeySpec(symKeyData, "AES");

        // retrieve random IV from start of the received message
        final byte[] ivData = new byte[blockSize];
        System.arraycopy(ivAndEncryptedMessage, 0, ivData, 0, blockSize);
        final IvParameterSpec iv = new IvParameterSpec(ivData);

        // retrieve the encrypted message itself
        final byte[] encryptedMessage = new byte[ivAndEncryptedMessage.length
                - blockSize];
        System.arraycopy(ivAndEncryptedMessage, blockSize,
                encryptedMessage, 0, encryptedMessage.length);

        cipher.init(Cipher.DECRYPT_MODE, symKey, iv);

        final byte[] encodedMessage = cipher.doFinal(encryptedMessage);

        // concatenate IV and encrypted message
        final String message = new String(encodedMessage,
                Charset.forName("UTF-8"));

        return message;
    } catch (InvalidKeyException e) {
        throw new IllegalArgumentException(
                "key argument does not contain a valid AES key");
    } catch (BadPaddingException e) {
        // you'd better know about padding oracle attacks
        return null;
    } catch (GeneralSecurityException e) {
        throw new IllegalStateException(
                "Unexpected exception during decryption", e);
    }
}

提醒那些获得Padding异常的人。确保使用正确的密钥长度。提示:看看Maarten的帖子:他的十六进制正好是32;)这并非巧合:)