【问题标题】:RSA Encryption Decryption in AndroidAndroid中的RSA加密解密
【发布时间】:2012-09-10 10:06:43
【问题描述】:

我正在 Android 中实现 RSA 加密和解密的演示。我可以很好地执行加密,但在解密时我得到一个异常:>>java.security.InvalidKeyException: unknown key type passed to RSA。

    KeyPairGenerator kpg;
    KeyPair kp;
    PublicKey publicKey;
    PrivateKey privateKey;
    byte [] encryptedBytes,decryptedBytes;
    Cipher cipher,cipher1;
    String encrypted,decrypted;

    public String RSAEncrypt (final String plain) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException 
    {
        kpg = KeyPairGenerator.getInstance("RSA");
        kpg.initialize(1024);
        kp = kpg.genKeyPair();
        publicKey = kp.getPublic();
        privateKey = kp.getPrivate();

        cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        encryptedBytes = cipher.doFinal(plain.getBytes());
        encrypted = new String(encryptedBytes);
        System.out.println("EEncrypted?????"+encrypted);
        return encrypted;

    }

    public String RSADecrypt (final String result) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException 
    {

        cipher1=Cipher.getInstance("RSA");
        cipher1.init(Cipher.DECRYPT_MODE, privateKey);
        decryptedBytes = cipher1.doFinal(result.getBytes());
        decrypted = new String(decryptedBytes);
        System.out.println("DDecrypted?????"+decrypted);
        return decrypted;

    }

我从这里调用函数:

encrypt.setOnClickListener(new OnClickListener()
        { 
            public void onClick(View arg0) 
            {
                    try
                    {
                        RSAEncrypt rsaencrypt=new RSAEncrypt();
                        rsaencrypt.RSAEncrypt(name);

                        result=rsaencrypt.RSAEncrypt(name);
                        Toast.makeText(getBaseContext(), result.toString(),Toast.LENGTH_SHORT).show();

                        System.out.println("Result:"+result);
                    }
                    catch(Exception e)
                    {
                        e.printStackTrace();
                        Toast.makeText(getBaseContext(), e.toString(),Toast.LENGTH_LONG).show();
                    }
            }
        });

        decrypt.setOnClickListener(new OnClickListener()
        { 
            public void onClick(View arg0) 
            {
                {
                    try
                    {
                        RSAEncrypt rsadecrypt=new RSAEncrypt();

                        rsadecrypt.RSADecrypt(result);

                        ans=rsadecrypt.RSADecrypt(result);
                        System.out.println("Result is"+ans);
                        Toast.makeText(getBaseContext(), ans.toString(),Toast.LENGTH_LONG).show();
                    }
                    catch(Exception e)
                    {
                        e.printStackTrace();
                        Toast.makeText(getBaseContext(), e.toString(),Toast.LENGTH_LONG).show();
                        System.out.println("Exception is>>"+e);
                    }
            }
        });

【问题讨论】:

    标签: android rsa public-key-encryption encryption


    【解决方案1】:

    在 RSA 中,您应该使用公钥进行加密,使用私钥进行解密。

    您的示例代码用于加密和解密公钥 - 这是行不通的。

    因此在解密部分你应该这样初始化密码:

    cipher1.init(Cipher.DECRYPT_MODE, privateKey);
    

    此外,您的代码还有第二个重大错误:

    您正在将具有二进制内容的字节数组转换为字符串。

    永远不要将二进制数据转换为字符串!

    字符串用于字符串字符,而不是二进制数据。如果您想将二进制数据打包成字符串,例如使用 Hex 或 Base64 将其编码为可打印字符。

    以下示例使用来自 org.apache.common.codec 包的十六进制编码器 - 必须安装第三方库。

    public byte[] RSAEncrypt(final String plain) throws NoSuchAlgorithmException, NoSuchPaddingException,
            InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        kpg = KeyPairGenerator.getInstance("RSA");
        kpg.initialize(2048);
        kp = kpg.genKeyPair();
        publicKey = kp.getPublic();
        privateKey = kp.getPrivate();
    
        cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        encryptedBytes = cipher.doFinal(plain.getBytes());
        System.out.println("EEncrypted?????" + new String(org.apache.commons.codec.binary.Hex.encodeHex(encryptedBytes)));
        return encryptedBytes;
    }
    
    public String RSADecrypt(final byte[] encryptedBytes) throws NoSuchAlgorithmException, NoSuchPaddingException,
            InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
    
        cipher1 = Cipher.getInstance("RSA");
        cipher1.init(Cipher.DECRYPT_MODE, privateKey);
        decryptedBytes = cipher1.doFinal(encryptedBytes);
        decrypted = new String(decryptedBytes);
        System.out.println("DDecrypted?????" + decrypted);
        return decrypted;
    }
    

    【讨论】:

    • 非常感谢..你是对的..我做错了..但现在我得到了异常>> System.err(416): java.security.InvalidKeyException: unknown key type传递给 RSA 请帮助我..在此先感谢..
    • 谢谢。只说一句话:键是对称的。因此,您可以使用公共编码然后使用私有解码(确保您将加密数据发送给谁),或者使用私有编码,然后使用公共解码(以确保谁向您发送了加密数据)。执行 2(使用 2 个不同的密钥集),允许您强制执行“从谁”和“对谁”安全方面。
    • “使用私有编码”的情况称为签名。但是您永远不应该直接签署数据 - 始终只签署数据,否则您可能会遇到一些攻击(请参阅 IT 安全文献)。
    • 总是只签什么?
    • “总是只签名哈希”(SHA-256 或 SHA-1 或 ...)
    【解决方案2】:

    以下是 Android 的示例:

    • 生成私有/公共 RSA 密钥对
    • 加密字符串
    • 解密加密字符串

    这些方法处理所有 base 64 编码/解码。

        public void TestEncryptData(String dataToEncrypt) {
            // generate a new public/private key pair to test with (note. you should only do this once and keep them!)
            KeyPair kp = getKeyPair();
    
            PublicKey publicKey = kp.getPublic();
            byte[] publicKeyBytes = publicKey.getEncoded();
            String publicKeyBytesBase64 = new String(Base64.encode(publicKeyBytes, Base64.DEFAULT));
    
            PrivateKey privateKey = kp.getPrivate();
            byte[] privateKeyBytes = privateKey.getEncoded();
            String privateKeyBytesBase64 = new String(Base64.encode(privateKeyBytes, Base64.DEFAULT));
    
            // test encryption
            String encrypted = encryptRSAToString(dataToEncrypt, publicKeyBytesBase64);
    
            // test decryption
            String decrypted = decryptRSAToString(encrypted, privateKeyBytesBase64);
        }
    
        public static KeyPair getKeyPair() {
            KeyPair kp = null;
            try {
                KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
                kpg.initialize(2048);
                kp = kpg.generateKeyPair();
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            return kp;
        }
    
        public static String encryptRSAToString(String clearText, String publicKey) {
            String encryptedBase64 = "";
            try {
                KeyFactory keyFac = KeyFactory.getInstance("RSA");
                KeySpec keySpec = new X509EncodedKeySpec(Base64.decode(publicKey.trim().getBytes(), Base64.DEFAULT));
                Key key = keyFac.generatePublic(keySpec);
    
                // get an RSA cipher object and print the provider
                final Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING");
                // encrypt the plain text using the public key
                cipher.init(Cipher.ENCRYPT_MODE, key);
    
                byte[] encryptedBytes = cipher.doFinal(clearText.getBytes("UTF-8"));
                encryptedBase64 = new String(Base64.encode(encryptedBytes, Base64.DEFAULT));
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            return encryptedBase64.replaceAll("(\\r|\\n)", "");
        }
    
        public static String decryptRSAToString(String encryptedBase64, String privateKey) {
    
            String decryptedString = "";
            try {
                KeyFactory keyFac = KeyFactory.getInstance("RSA");
                KeySpec keySpec = new PKCS8EncodedKeySpec(Base64.decode(privateKey.trim().getBytes(), Base64.DEFAULT));
                Key key = keyFac.generatePrivate(keySpec);
    
                // get an RSA cipher object and print the provider
                final Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING");
                // encrypt the plain text using the public key
                cipher.init(Cipher.DECRYPT_MODE, key);
    
                byte[] encryptedBytes = Base64.decode(encryptedBase64, Base64.DEFAULT);
                byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
                decryptedString = new String(decryptedBytes);
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            return decryptedString;
        }
    

    【讨论】:

      【解决方案3】:

      我的班级:

      package com.infovale.cripto;
      
      import java.io.UnsupportedEncodingException;
      import java.math.BigInteger;
      import java.security.InvalidKeyException;
      import java.security.KeyPair;
      import java.security.KeyPairGenerator;
      import java.security.NoSuchAlgorithmException;
      import java.security.PrivateKey;
      import java.security.PublicKey;
      import java.util.Arrays;
      
      import javax.crypto.BadPaddingException;
      import javax.crypto.Cipher;
      import javax.crypto.IllegalBlockSizeException;
      import javax.crypto.NoSuchPaddingException;
      
      public class RSA {
      
      KeyPairGenerator kpg;
      KeyPair kp;
      PublicKey publicKey;
      PrivateKey privateKey;
      byte[] encryptedBytes, decryptedBytes;
      Cipher cipher, cipher1;
      String encrypted, decrypted;
      
      public String Encrypt (String plain) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException 
      {
          kpg = KeyPairGenerator.getInstance("RSA");
          kpg.initialize(1024);
          kp = kpg.genKeyPair();
          publicKey = kp.getPublic();
          privateKey = kp.getPrivate();
      
          cipher = Cipher.getInstance("RSA");
          cipher.init(Cipher.ENCRYPT_MODE, publicKey);
          encryptedBytes = cipher.doFinal(plain.getBytes());
      
          encrypted = bytesToString(encryptedBytes);
          return encrypted;
      
      }
      
      public String Decrypt (String result) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException 
      {           
      
          cipher1=Cipher.getInstance("RSA");
          cipher1.init(Cipher.DECRYPT_MODE, privateKey);
          decryptedBytes = cipher1.doFinal(stringToBytes(result));
          decrypted = new String(decryptedBytes);
          return decrypted;
      
      }
      
      public  String bytesToString(byte[] b) {
          byte[] b2 = new byte[b.length + 1];
          b2[0] = 1;
          System.arraycopy(b, 0, b2, 1, b.length);
          return new BigInteger(b2).toString(36);
      }
      
      public  byte[] stringToBytes(String s) {
          byte[] b2 = new BigInteger(s, 36).toByteArray();
          return Arrays.copyOfRange(b2, 1, b2.length);
      }
      }
      

      【讨论】:

        【解决方案4】:

        使用RSAEcvypt方法时,填写PublicKey和private key。 当您解密生成的字节 [] 时,您的 publicKey 和 privateKey 为 NULL。 因此,您会收到此错误。

        您应该使用静态密钥;

        enter code here
        
        KeyPairGenerator kpg;
        KeyPair kp;
        static PublicKey publicKey;
        static PrivateKey privateKey;
        byte [] encryptedBytes,decryptedBytes;
        Cipher cipher,cipher1;
        String encrypted,decrypted;
        

        【讨论】:

        • 这些是类属性,因为访问这些键的方法不是静态的,因此属性不必是静态的。事实上,当您可能需要创建具有不同数据值的多个类实例时,拥有静态属性是一个非常糟糕的选择。
        【解决方案5】:

        我认为问题在于您应该使用相同的密钥对来加密和解密密码。参考JavaDoc:

         genKeyPair() This will generate a new key pair every time it is called.
        

        【讨论】:

        • @jaredzhang..我编辑了我的代码..但我得到了同样的异常..请查看我编辑的代码..
        • @jaredzhang..我认为你是对的..但问题是现在我得到 java.lang.NullPointerException..
        • 您的新代码似乎不清楚,请确保您用于解密的私钥与您之前生成的相同。
        • @jaredzhang..嗨..我再次编辑了我的代码..所以..你看起来很清楚..请帮助我..非常感谢..也看看我的问题..我得到的例外现在也不同....
        • @jaredzhang 所以这不能用于将数据从一个应用程序发送到另一个应用程序,因为接收器应用程序将调用 genKeyPair() 并创建不同的密钥。有什么解决办法吗?
        猜你喜欢
        • 1970-01-01
        • 2015-02-27
        • 1970-01-01
        • 2012-03-13
        • 2015-03-16
        • 1970-01-01
        • 2011-12-10
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多