2011-06-30 114 views
11

我是密码技术的新手。我发现这个代码做对称加密。使用AES 256和128的Java对称密钥加密

byte[] key = //... secret sequence of bytes 
byte[] dataToSend = ... 
Cipher c = Cipher.getInstance("AES"); 
SecretKeySpec k = new SecretKeySpec(key, "AES"); 
c.init(Cipher.ENCRYPT_MODE, k); 
byte[] encryptedData = c.doFinal(dataToSend); 

它的工作。在这里我可以使用我自己的密码。那就是我所需要的。但我不知道如何做128或256对称Enctryption。 如何在我的代码中使用128和256密钥?

+0

我真的不知道,但我认为使用一个256字节的密钥将完成这项工作。 –

+0

实际上只有16个字节(128位)的密钥在我的代码中工作。 – Bhuban

+0

更大的按键是什么“不工作”?你有例外吗?哪一个?它的消息和堆栈跟踪是什么? –

回答

13

AES使用128位还是256位模式取决于您的密钥的大小,它必须是128位或256位长。通常,您不会将密码用作密钥,因为根据需要,密码很少具有确切的长度。相反,您可以使用某个密钥派生函数从密码中导出加密密钥。

很简单的例子:取你的密码的MD5得到128位密钥。 如果您需要256位密钥,则可以使用SHA-256获取密码的256位散列值。密钥派生函数通常运行这种散列几百次,并使用额外的盐。详情请查阅http://en.wikipedia.org/wiki/Key_derivation_function

另请注意:要运行比128位更强的加密,您需要从http://www.oracle.com/technetwork/java/javase/downloads/index.html下载并安装'Java加密扩展(JCE)无限强度管辖策略文件6'。

+5

MD5?今天早上我在1996年醒来了吗? SHA系列具有产生128,256,348和512位哈希的算法。 –

+4

@Peter:这只是一个简单的例子,如何获得从密码计算出来的128位密钥。如果你的密码少于16个字节,你可以将它填充到16个字节。你挑选不重要的细节。 (无论如何,我已经更新了我的答案,说使用SHA-256从密码获得256位密钥) –

+1

@Peter,哈哈哈,是的,我只是讨厌看到MD5的任何东西,但遗产代码,并不认为它应该是推荐给初学者;它已经破裂很久了。 –

2

您可以使用一个简单的KeyGenerator对象是这样的:

KeyGenerator generator = KeyGenerator.getInstance("AES/CTR/PKCS5PADDING"); 
generator.init(128); 
SecretKey key = generator.generateKey(); 
Cipher cipher = Cipher.getInstance("AES"); 
cipher.init(Cipher.ENCRYPT_MODE, key); 
... 
+1

这里如何使用我自己的密码? – Bhuban

1

Java's docs for Cipher.init(...)

公众最终无效的init(INT OPMODE, 键键)

抛出: InvalidKeyException异常 - 如果给定密钥不适合初始化 此密码,或者此密码为 初始化为解密和 要求 不能从给定的 键来确定算法参数,或者如果给定的键具有密钥大小 超过最大允许 密钥大小(如从 配置的仲裁策略文件确定)。

对我来说,这意味着,马亭Courteaux在他的评论中说,你应该使用256位的密钥(即含32个字节的字节数组初始化SecretKeySpec)和密码会接受它,使用它,或拒绝它并抛出一个异常,如果它的大小是不可接受的。

如果您遇到异常,可能是因为您尚未安装无限强度的加密文件(默认JDK安装允许此crypto spec document中记录的128位密钥)。下载无限强度加密包here

+0

是的,我的代码可以只需要16个字节或128位。所以这是我的问题如何使用256位密钥? – Bhuban

+0

我编辑了我的答案 –

+0

谢谢。它的工作现在。你的回答非常有帮助。 – Bhuban

0
public class CipherUtils 
{ 
    private static byte[] key = { 
      0x74, 0x68, 0x69, 0x73, 0x49, 0x73, 0x41, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4b, 0x65, 0x79 
    };//"thisIsASecretKey"; 

    public static String encrypt(String strToEncrypt) 
    { 
     try 
     { 
      Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); 
      final SecretKeySpec secretKey = new SecretKeySpec(key, "AES"); 
      cipher.init(Cipher.ENCRYPT_MODE, secretKey); 
      final String encryptedString = Base64.encodeBase64String(cipher.doFinal(strToEncrypt.getBytes())); 
      return encryptedString; 
     } 
     catch (Exception e) 
     { 
      e.printStackTrace(); 
     } 
     return null; 
    } 
} 
+0

我有几个问题。 1.该密钥是唯一可用于解密的密钥,对吧? (可能是这个问题的一个明显的答案 - 只要确保)2.如果使用相同的密钥(运行该方法的两个不同时间)对相同的数据进行加密,它是否会呈现不同的加密字节? – raddevus

+0

好吧,我转换了这段代码,并找出了自己的答案。另外,有趣的是,OWASP示例(https://www.owasp.org/index.php/Using_the_Java_Cryptographic_Extensions)直接提到了使用IV(初始化向量),但它并未在此答案的代码中使用。 Ce la vie。 – raddevus

+0

不要硬编码密钥。任何有权访问编译代码的人都可以轻松使用它。 – Mike

6

对于128位

下面的方法是加密的字符串(valueEnc)与AES加密的答案:

private static final String ALGORITHM = "AES"; 

public String encrypt(final String valueEnc, final String secKey) { 

    String encryptedVal = null; 

    try { 
     final Key key = generateKeyFromString(secKey); 
     final Cipher c = Cipher.getInstance(ALGORITHM); 
     c.init(Cipher.ENCRYPT_MODE, key); 
     final byte[] encValue = c.doFinal(valueEnc.getBytes()); 
     encryptedVal = new BASE64Encoder().encode(encValue); 
    } catch(Exception ex) { 
     System.out.println("The Exception is=" + ex); 
    } 

    return encryptedVal; 
} 

下一个方法将解密的AES加密字符串(encryptedVal) :

public String decrypt(final String encryptedValue, final String secretKey) { 

    String decryptedValue = null; 

    try { 

     final Key key = generateKeyFromString(secretKey); 
     final Cipher c = Cipher.getInstance(ALGORITHM); 
     c.init(Cipher.DECRYPT_MODE, key); 
     final byte[] decorVal = new BASE64Decoder().decodeBuffer(encryptedValue); 
     final byte[] decValue = c.doFinal(decorVal); 
     decryptedValue = new String(decValue); 
    } catch(Exception ex) { 
     System.out.println("The Exception is=" + ex); 
    } 

    return decryptedValue; 
} 

The secKey是一个128位密钥,编码在BASE64Encoder中。在以下方法BASE64Decoder生成一个合适的128位密钥

private Key generateKeyFromString(final String secKey) throws Exception { 
    final byte[] keyVal = new BASE64Decoder().decodeBuffer(secKey); 
    final Key key = new SecretKeySpec(keyVal, ALGORITHM); 
    return key; 
} 
+1

您已经忘记使用初始化矢量,并且您也没有指定要使用的AES的模式和填充。虽然这是对问题的回答,但请注意,这不是安全使用加密。 –