【发布时间】:2016-06-19 10:08:38
【问题描述】:
我尝试使用 RSA-AES 创建混合加密,但现在我在此编码中遇到了问题。从这段代码中,我尝试创建一个 RSA 密钥对、私钥和公钥。之后我应该生成一个随机密钥对称算法 AES 然后我必须创建一个 AES 密码才能使用 AES 密钥加密文本字符串。那么文本用AES密钥加密后,需要用RSA公钥加密AES密钥,用RSA私钥解密加密的AES密钥。最后解密使用 AES 密钥输入的文本消息,以便阅读该消息。我想我在编码中遗漏了一些东西。请帮帮我。
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.spec.EncodedKeySpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
public class HybridAesRsa
{
private Cipher cipher;
// RSA keys will be generated when the client and server connect
private PrivateKey myPrivateKey;
private byte[] myPublicKey;
private byte[] interlocutorPublicKey = null;
// Strings are encoded / decoded in BASE64
private BASE64Decoder b64decoder = new BASE64Decoder();
private BASE64Encoder b64encoder = new BASE64Encoder();
public HybridAesRsa()
{
try
{
cipher = Cipher.getInstance("RSA");
Security.addProvider(new BouncyCastleProvider());
}
catch (Exception ex){
Logger.getLogger(HybridAesRsa.class.getName()).log(Level.SEVERE,null,ex);
}
}
// Generate the pair of public and private keys using 1024 bytes
public KeyPair generateKey() throws Exception
{
KeyPair keyPair = null;
try{
//generate RSA key pair
KeyPairGenerator rsaKeyGen = KeyPairGenerator.getInstance("RSA");
rsaKeyGen.initialize(1024);
keyPair = rsaKeyGen.generateKeyPair();
//RSA public and private key
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
//System.out.println("RSA public key 1 ---> "+publicKey);
//System.out.println("RSA private key 1 ---> " +privateKey);
//for Chatting
myPublicKey = publicKey.getEncoded();
setMyPrivateKey(privateKey);
//Generating a random key symmetrical algorithm AES
KeyGenerator aesKeyGenerator = KeyGenerator.getInstance("AES");
SecureRandom random = new SecureRandom();
aesKeyGenerator.init(random);
SecretKey aesSecretKey = aesKeyGenerator.generateKey();
/*//The key is presented in a byte array
byte[] symmetricKey = aesSecretKey.getEncoded();
//Printing out the generated key
System.out.println("\nAES symmetric key --> " + symmetricKey); */
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(HybridAesRsa.class.getName()).log(Level.SEVERE,null,ex);
}
return keyPair;
}
// Encrypts text using public key
public String encrypt(String text, PublicKey publicKey, SecretKey aesSecretKey ) throws Exception
{
//Creating an AES cipher in order to encrypt a text string with the AES key
Cipher aesCipher = Cipher.getInstance("AES");
aesCipher.init(Cipher.ENCRYPT_MODE, aesSecretKey);
//Now that the text is encrypted with the AES key, then the AES key needs to be encrypted with the RSA public key
Cipher rsaCipher = Cipher.getInstance("RSA");
rsaCipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedAESkey = rsaCipher.doFinal(aesSecretKey.getEncoded());
//Printing out the encrypted AES key
System.out.println("\nAES key encrypted with RSA --> " + encryptedAESkey);
return text;
}
// Use the public key to encrypt the interlocutor
public String encrypt(String text) throws Exception
{
return encrypt(text, bytesToPublicKey(interlocutorPublicKey), null);
}
// Decrypts text using private key
public String decrypt(String text, PrivateKey privatekey) throws Exception
{
// Now the encrypted AES key needs to be decrypted with the RSA private key
Cipher rsaCipher2 = Cipher.getInstance("RSA");
rsaCipher2.init(Cipher.DECRYPT_MODE, privatekey);
byte[] encryptedAESkey = null;
byte[] decryptedAESkey = rsaCipher2.doFinal(encryptedAESkey);
//Print out the decrypted AES key
System.out.println("AES key decrypted with RSA private key --> " + decryptedAESkey);
//And finally decrypt the text message entered with AES key in order to read the message.
Cipher aesCipher2 = Cipher.getInstance("AES");
Key aesSecretKey = null;
aesCipher2.init(Cipher.DECRYPT_MODE,aesSecretKey);
byte[] encrypt = null;
byte [] decrypt = aesCipher2.doFinal(encrypt);
return text;
}
// Use my private key to decrypt
public String decrypt(String text) throws Exception
{
return decrypt(text, myPrivateKey);
}
// Public Key the caller is sent in byte [ ] and converted into a PublicKey object
public static PublicKey bytesToPublicKey(byte[] publicKeybytes)
{
PublicKey publicKey = null;
try {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeybytes);
publicKey = keyFactory.generatePublic(publicKeySpec);
}
catch (InvalidKeySpecException ex) {
Logger.getLogger(HybridAesRsa.class.getName()).log(Level.SEVERE, null, ex);
}
catch (NoSuchAlgorithmException ex){
Logger.getLogger(HybridAesRsa.class.getName()).log(Level.SEVERE, null, ex);
}
return publicKey;
}
// Test
public static void main(String[] args){
try {
HybridAesRsa crypto = new HybridAesRsa();
KeyPair keyPair = crypto.generateKey();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
KeyGenerator aesKeyGenerator = KeyGenerator.getInstance("AES");
SecretKey aesSecretKey = aesKeyGenerator.generateKey();
byte[] publicKeyBytes = publicKey.getEncoded();
byte[] privateKeyBytes = privateKey.getEncoded();
byte[] symmetricKey = aesSecretKey.getEncoded();
System.out.println("RSA Public key: " + new BigInteger(publicKeyBytes));
System.out.println("RSA Private key: " + new BigInteger(privateKeyBytes));
System.out.println("AES symmetric key --> " + new BigInteger(symmetricKey));
Cipher aesCipher = Cipher.getInstance("AES");
aesCipher.init(Cipher.ENCRYPT_MODE, aesSecretKey);
String testeMsg = "As a seed knows how to make a flower ? I love you.";
byte[] encrypt = aesCipher.doFinal(testeMsg.getBytes());
Cipher rsaCipher = Cipher.getInstance("RSA");
rsaCipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedAESkey = rsaCipher.doFinal(aesSecretKey.getEncoded());
String encrypted = crypto.encrypt(testeMsg, bytesToPublicKey(publicKeyBytes), aesSecretKey);
System.out.println("Encrypted Text: " + encrypted);
String decrypted = crypto.decrypt(encrypted, keyPair.getPrivate());
System.out.println("Decrypted Text: " + decrypted);
}
catch (Exception ex)
{
Logger.getLogger(HybridAesRsa.class.getName()).log(Level.SEVERE, null, ex);
}
}
public byte[] getMyPublicKey(){
return myPublicKey;
}
public void setMyPublicKey(byte[] myPublicKey) {
this.myPublicKey = myPublicKey;
}
public PrivateKey getMyPrivateKey(){
return myPrivateKey;
}
public byte[] getInterlocutorPublicKey(){
return interlocutorPublicKey;
}
public boolean hasInterlocutorPublicKey(){
return interlocutorPublicKey!=null;
}
public void setInterlocutorPublicKey(byte[] interlocutorPublicKey){
this.interlocutorPublicKey = interlocutorPublicKey;
}
public void setMyPrivateKey(PrivateKey aMyPrivateKey){
myPrivateKey = aMyPrivateKey;
}
}
这里是这段代码的错误
Jun 19, 2016 5:50:14 PM HybridAesRsa main
SEVERE: null
java.lang.IllegalArgumentException: Null input buffer
at javax.crypto.Cipher.doFinal(Cipher.java:2117)
at HybridAesRsa.decrypt(HybridAesRsa.java:125)
at HybridAesRsa.main(HybridAesRsa.java:204)
【问题讨论】:
-
[OT] 有趣的是,看到一个人如何在 Java 中编码 RSA,而在很多地方都必须使用“BigInteger”。在像 Python 这样的 PL 中,大整数操作符就像小整数操作符一样,因此对程序员来说更方便。 (参见我的 RSA 代码 s13.zetaboards.com/Crypto/topic/7234475/1/)
-
一般建议:始终使用完全限定的密码字符串。
Cipher.getInstance("RSA");可能会产生不同的密码,具体取决于默认的安全提供程序。现在,您应该使用 OAEP 而不是默认的 PKCS#1 v1.5 填充。所以你可能应该使用Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding"); -
一般建议:始终使用完全限定的密码字符串。
Cipher.getInstance("AES");可能会产生不同的密码,具体取决于默认的安全提供程序。它最有可能导致"AES/ECB/PKCS5Padding",但并非必须如此。如果它发生变化,您将失去不同 JVM 之间的兼容性。 -
切勿使用ECB mode。它是确定性的,因此在语义上不安全。您至少应该使用像CBC 或CTR 这样的随机模式。最好对您的密文进行身份验证,以免像padding oracle attack 这样的攻击是不可能的。这可以通过 GCM 或 EAX 等经过身份验证的模式或encrypt-then-MAC 方案来完成。
标签: java encryption aes rsa hybrid