【问题标题】:Hybrid RSA-AES encryption混合 RSA-AES 加密
【发布时间】: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。它是确定性的,因此在语义上不安全。您至少应该使用像CBCCTR 这样的随机模式。最好对您的密文进行身份验证,以免像padding oracle attack 这样的攻击是不可能的。这可以通过 GCM 或 EAX 等经过身份验证的模式或encrypt-then-MAC 方案来完成。

标签: java encryption aes rsa hybrid


【解决方案1】:

你有这个代码:

byte[] encrypt = null;
byte [] decrypt = aesCipher2.doFinal(encrypt);

您尝试使用初始化为 null 的缓冲区进行加密。这是不可能的。

异常很明显:

java.lang.IllegalArgumentException: Null input buffer

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-11
    • 1970-01-01
    • 1970-01-01
    • 2017-04-26
    相关资源
    最近更新 更多