解密时RSA BadPaddingException

时间:2014-05-14 00:01:01

标签: java encryption rsa public-key-encryption javacard

我正在使用我在桌面应用上生成的公钥在java智能卡上加密一些字节的数据,但是当我尝试在桌面上解密数据时,我得到BadPaddingException : Data must start with zero,我读到这个可能是由于使用了错误的私钥来解密数据。

  1. 首先,我在桌面应用上生成了一个公钥/私钥对,并使用以下代码将它们加载到智能卡上(以BigInteger类型生成,我将它们转换为十六进制,从十六进制转换为字节数组):

    void keyGen(String ID)throws Exception{
        // where ID is the name of the user 
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
        kpg.initialize(512);
        KeyPair kp = kpg.genKeyPair();
        this.pubKey = (RSAPublicKey) kp.getPublic();
        this.privKey = (RSAPrivateKey) kp.getPrivate();
    
        KeyFactory fact = KeyFactory.getInstance("RSA");
        this.pub = fact.getKeySpec(kp.getPublic(), RSAPublicKeySpec.class);
        this.priv = fact.getKeySpec(kp.getPrivate(),  RSAPrivateKeySpec.class);
    
        saveToFile(ID+".pub", pub.getModulus(),  pub.getPublicExponent());
        saveToFile(ID+".priv", priv.getModulus(),  priv.getPrivateExponent());
    
    }
    
  2. 这是savetofile函数:

        public void saveToFile(String fileName,  BigInteger mod, BigInteger exp) throws IOException {
              ObjectOutputStream oout = new ObjectOutputStream(
                new BufferedOutputStream(new FileOutputStream(fileName)));
              try {
                oout.writeObject(mod);
                oout.writeObject(exp);
              } catch (Exception e) {
                throw new IOException();
              } finally {
                oout.close();
              }
            }
    

    这是用于在智能卡上存储公钥的行:

    Main.sRmi.setPub(Crypto.hexStringToByteArray(Main.crypto.getPubMod().toString(16)), 
     toByteArray("0"+Main.crypto.getPubexp().toString(16)));
    

    (将零添加到字符串中,因为我们无法将奇数十六进制的字符串转换为字节)

    1. 然后我尝试使用卡内的公钥加密数据,这是我正在使用的功能:

      private Cipher cipherRSA = Cipher.getInstance(Cipher.ALG_RSA_PKCS1, false);
      private byte[] cipherText = new byte[64];
      
      public byte[] encrypt(byte[] clearText){
      
          cipherRSA.init(rsa_PublicKey, Cipher.MODE_ENCRYPT);
          cipherRSA.doFinal(clearText, (short)0,  (short)clearText.length,cipherText, (short)0 );
          return cipherText;
      }
      
    2. 然后我尝试在另一个桌面应用程序上获取此加密值,并使用我正在从文件中读取的私钥对其进行解密:

    3. 这是我从文件中读取私钥的方式:

      public void init (String ID ) throws FileNotFoundException, IOException, Exception{
      
          Object o[] = openFile(ID+".pub");
          setPubMod((BigInteger) o[0]);
          setPubexp((BigInteger) o[1]);
          RSAPublicKeySpec keySpec = new RSAPublicKeySpec(this.pubMod, this.pubexp);
          KeyFactory fact = KeyFactory.getInstance("RSA");
          pubKey = (RSAPublicKey) fact.generatePublic(keySpec);
          o = openFile(ID+".priv");
          setPrivMod((BigInteger) o[0]);
          setPrivexp((BigInteger) o[1]);
          RSAPrivateKeySpec keySpec1 = new RSAPrivateKeySpec(this.privMod, this.privexp);
          fact = KeyFactory.getInstance("RSA");
          privKey = (RSAPrivateKey) fact.generatePrivate(keySpec1);
          cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING"); 
          cipher.init(Cipher.ENCRYPT_MODE, pubKey);
      }
      

      在BigInteger变量中获取私钥后,我使用以下方法解密:

      public byte[] rsaDecrypt(byte[] data) throws Exception, BadPaddingException {
      
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, privKey);
            byte[] clearData = cipher.doFinal(data);
            return clearData;
          }
      

      总结一下,我用BigInteger格式创建一个密钥对,我将BigInteger变量保存到两个BigIntegers的序列化数组中,供其他桌面应用程序使用,然后我将它们转换为Hexa String,然后转换为我放入智能卡的字节数组。

      有人可以告诉我这个程序有什么问题吗?太多了吗?有没有更好的方法呢?


      我想我知道问题在哪里,它是存储在智能卡内部的密钥,按照我明显无法正常工作的方式进行转换,看看我是如何从卡上读取它并将其打印出来并获得完全不同的结果,现在的问题是,如何将在java.crypto上创建的公钥(在BigInteger中)成功导出到智能卡,其中公钥存储在字节中?

      我发现了这个:

      设置密钥的公共指数值。明文数据格式是big-endian和右对齐(最低有效位是最后一个字节的最低有效位)。输入指数数据被复制到内部表示中。

      那么如何将一个大整数转换为这个大端字节格式呢?

      现在我正在尝试设置公钥,这是我正在执行的代码:

      public void setPub(byte[] expo,byte[] mod){
          rsa_PublicKey.clearKey();
          rsa_PublicKey.setExponent(expo, (short)0, (short)expo.length);
          rsa_PublicKey.setModulus(mod, (short)0, (short)mod.length);
      }
      

      其中expo是一个65字节的数组,mod是一个由密钥生成的3字节数组,但是我收到了这个错误:

      Exception in thread "AWT-EventQueue-0" java.lang.UnsatisfiedLinkError: com.sun.javacard.impl.NativeMethods.getCurrentContext()B
      at com.sun.javacard.impl.NativeMethods.getCurrentContext(Native Method)
      at com.sun.javacard.impl.PrivAccess.getCurrentAppID(PrivAccess.java:454)
      at javacard.framework.CardRuntimeException.<init>(CardRuntimeException.java:46)
      at javacard.security.CryptoException.<init>(DashoA10*..:25)
      at com.sun.javacard.javax.smartcard.rmiclient.CardObjectFactory.throwIt(Unknown Source)
      at com.sun.javacard.javax.smartcard.rmiclient.CardObjectFactory.throwException(Unknown Source)
      at com.sun.javacard.javax.smartcard.rmiclient.CardObjectFactory.getObject(Unknown Source)
      at com.sun.javacard.rmiclientlib.JCRemoteRefImpl.parseAPDU(Unknown Source)
      at com.sun.javacard.rmiclientlib.JCRemoteRefImpl.invoke(Unknown Source)
      at sid2.CompteurImpl_Stub.setPub(Unknown Source)
      at sid2.ServerRmi.setPub(ServerRmi.java:27)
      at AddCard$2.actionPerformed(AddCard.java:160)
      

      这就是生成密钥priv和pub的方式:

      KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
          kpg.initialize(512);
          KeyPair kp = kpg.genKeyPair();
          this.pubKey = kp.getPublic();
          this.privKey = kp.getPrivate();
      
          KeyFactory fact = KeyFactory.getInstance("RSA");
          this.pub = fact.getKeySpec(kp.getPublic(), RSAPublicKeySpec.class);
          this.priv = fact.getKeySpec(kp.getPrivate(),  RSAPrivateKeySpec.class);
      

1 个答案:

答案 0 :(得分:1)

“其中expo是一个65字节的数组,mod是一个由密钥生成的3字节数组,但是我收到了这个错误:......”

难怪你得到错误,指数通常比模数更短,模数总是与键大小相同。您正在切换模数和指数。