如何将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; }
如果有人可以提供帮助,我会非常感激。
由于这些特殊原因,没有完整性检查
- 用例并不明显。
-
"AES/GCM/NoPadding"
模式仅适用于Java 7以上版本 - 它取决于用户是否要部署例如HMAC和/或AESCMAC(推荐)。
- 它至少需要一个额外的钥匙和两个完整的通行证。
如果您在双方都实现了GCM模式 – 例如在Java 6上使用Bouncy Castle – 请继续使用它,因为它更加安全(只要“IV”非常独特)。 改变实施应该很容易。
有关加密的实施说明
- 当在无限制的客户端/服务器角色中使用时,这种实现是不安全的,因为填充oracle攻击(它们平均每字节或更低,需要128次尝试,与算法或密钥大小无关)。 您需要在加密数据上使用MAC,HMAC或签名,并在解密之前对其进行validation以在客户端/服务器模式下进行部署。
- 如果解密失败,Decrypt将返回null。 这只能表示一个填充exception,应该对其进行充分处理(我是否警告填充oracle攻击?)
- 无效的密钥将作为
InvalidArgumentException
返回。 - 所有其他与安全性相关的exception都“在表下扫描”,因为这意味着Java运行时环境无效。 例如,每个Java SE实现都需要支持
"UTF-8"
和"AES/CBC/PKCS5Padding"
。
其他一些说明
- 请不要尝试相反的方法并将字节直接插入到encrypt方法的输入字符串中(例如,使用
new String(byte[])
)。 该方法可能会无声地失败! - 针对可读性进行了优化。 如果您更喜欢速度和更好的内存占用,请选择Base64流和
CipherStream
实现。 - 您至少需要Java 6 SE或兼容才能运行此代码。
- 对于超过128位的AES密钥大小,加密/解密可能会失败,因为您可能需要用于无限制加密的策略文件(可从Oracle获得)
- 导出加密时要小心政府规定。
- 此实现使用hex键而不是base64键,因为它们足够小,hex更容易手动编辑/validation。
- 使用从JDK检索的hex和base64编码/解码,无需任何外部库。
- 优步易于使用,但当然不是非常面向对象,没有加密/解密中使用的对象实例的缓存。 随意重构。
好的,这里有一些代码……
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;)这不是巧合:)