如何将String转换为SecretKey

我想将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; } 

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

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

  1. 用例并不明显。
  2. "AES/GCM/NoPadding"模式仅适用于Java 7以上版本
  3. 它取决于用户是否要部署例如HMAC和/或AESCMAC(推荐)。
  4. 它至少需要一个额外的钥匙和两个完整的通行证。

如果您在双方都实现了GCM模式 – 例如在Java 6上使用Bouncy Castle – 请继续使用它,因为它更加安全(只要“IV”非常独特)。 改变实施应该很容易。

有关加密的实施说明

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

其他一些说明

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

好的,这里有一些代码……

  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!"); } 

这是使用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的post:他的hex正好是32;)这不是巧合:)