This discussion is archived
10 Replies Latest reply: Mar 21, 2012 2:27 PM by 918757 RSS

javax.crypto.BadPaddingException: Data must start with zero

918757 Newbie
Currently Being Moderated
Here is my problem, I have a java card wich contains a public and private key. I try to extract the public key from the card, so first thing I do is get the modulus and the exponent of the card and regenerate a public key with it. Then, I try to decrypt a previously encrypted byte array and I get the Data must start with zero error. Here is the part of my code that does that job
cmdApdu = new CommandAPDU(commande2);
          r = channel.transmit(cmdApdu);
          byte[] temp = r.getData();
          byte[] modulus = Arrays.copyOfRange(temp, 3, temp.length);
          byte[] publicExponent = Arrays.copyOfRange(temp, 0, 3);
          
          byte[] modulus2 = new byte[65];
          modulus2[0] = (byte)0x00;
          for(int i = 1 ; i <= modulus.length; i++){
               modulus2[i] = modulus[i-1];
          }
          
          RSAPublicKeySpec spec = new RSAPublicKeySpec(new BigInteger(modulus2), new BigInteger(publicExponent));
          
          KeyFactory kf = KeyFactory.getInstance("RSA");
          
          Key pubKey = kf.generatePublic(spec);
          System.out.println(pubKey.toString());
          
          Cipher cipher = Cipher.getInstance("RSA");
          
          cipher.init(Cipher.DECRYPT_MODE, pubKey);
          
          byte[] encrypted = {(byte)0x8E, (byte)0x44, (byte)0x6E, (byte)0x42, (byte)0xF1, 
                    (byte)0xB7, (byte)0x0B, (byte)0x12, (byte)0x38, (byte)0x75, (byte)0x3A, 
                    (byte)0x50, (byte)0x3E, (byte)0x84, (byte)0x02, (byte)0x88, (byte)0xBC, 
                    (byte)0x0B, (byte)0x7A, (byte)0xFF, (byte)0x2F, (byte)0x39, (byte)0xE8, 
                    (byte)0x64, (byte)0xA4, (byte)0x3E, (byte)0x44, (byte)0x35, (byte)0x16, 
                    (byte)0xB1, (byte)0x16, (byte)0x49, (byte)0xDE, (byte)0xF9, (byte)0x73, 
                    (byte)0xFF, (byte)0x96, (byte)0x07, (byte)0x65, (byte)0xF0, (byte)0x4B, 
                    (byte)0xA8, (byte)0x7C, (byte)0x26, (byte)0xB6, (byte)0xBE, (byte)0xA5, 
                    (byte)0x90, (byte)0xBC, (byte)0xBC, (byte)0xD1, (byte)0x2C, (byte)0xF8, 
                    (byte)0x7B, (byte)0x11, (byte)0x6E, (byte)0x87, (byte)0xD4, (byte)0x97, 
                    (byte)0x04, (byte)0x96, (byte)0xA5, (byte)0x2E, (byte)0x11};
          byte[] decrypted = cipher.doFinal(encrypted);
On my card, it is a RSA_CRT algorithm, does that creat any problem?
I add a 0x00 at the beggening of the modulus because otherwise, it makes a 511 bits key because it is negative or something, is it ok to do that? (It was a previous bug I had and got that solution from the forum BadPaddingException problem
The key on my card should be a 2048 bits size key but my pubKey.tostring() tells me that.
Sun RSA public key, 512 bits. Would that be normal?

Thx for your help cheers!

Edited by: FrancisOL on Mar 19, 2012 10:15 AM

Edited by: sabre150 on Mar 19, 2012 5:20 PM

Moderator action : added [ code] tags to make the code readable.
  • 1. Re: javax.crypto.BadPaddingException: Data must start with zero
    sabre150 Expert
    Currently Being Moderated
    FrancisOL wrote:
    Here is my problem, I have a java card wich contains a public and private key. I try to extract the public key from the card, so first thing I do is get the modulus and the exponent of the card and regenerate a public key with it. Then, I try to decrypt a previously encrypted byte array and I get the Data must start with zero error. Here is the part of my code that does that job
    cmdApdu = new CommandAPDU(commande2);
              r = channel.transmit(cmdApdu);
              byte[] temp = r.getData();
              byte[] modulus = Arrays.copyOfRange(temp, 3, temp.length);
              byte[] publicExponent = Arrays.copyOfRange(temp, 0, 3);
              
              byte[] modulus2 = new byte[65];
              modulus2[0] = (byte)0x00;
              for(int i = 1 ; i <= modulus.length; i++){
                   modulus2[i] = modulus[i-1];
              }
              
              RSAPublicKeySpec spec = new RSAPublicKeySpec(new BigInteger(modulus2), new BigInteger(publicExponent));
              
              KeyFactory kf = KeyFactory.getInstance("RSA");
              
              Key pubKey = kf.generatePublic(spec);
              System.out.println(pubKey.toString());
              
              Cipher cipher = Cipher.getInstance("RSA");
              
              cipher.init(Cipher.DECRYPT_MODE, pubKey);
              
              byte[] encrypted = {(byte)0x8E, (byte)0x44, (byte)0x6E, (byte)0x42, (byte)0xF1, 
                        (byte)0xB7, (byte)0x0B, (byte)0x12, (byte)0x38, (byte)0x75, (byte)0x3A, 
                        (byte)0x50, (byte)0x3E, (byte)0x84, (byte)0x02, (byte)0x88, (byte)0xBC, 
                        (byte)0x0B, (byte)0x7A, (byte)0xFF, (byte)0x2F, (byte)0x39, (byte)0xE8, 
                        (byte)0x64, (byte)0xA4, (byte)0x3E, (byte)0x44, (byte)0x35, (byte)0x16, 
                        (byte)0xB1, (byte)0x16, (byte)0x49, (byte)0xDE, (byte)0xF9, (byte)0x73, 
                        (byte)0xFF, (byte)0x96, (byte)0x07, (byte)0x65, (byte)0xF0, (byte)0x4B, 
                        (byte)0xA8, (byte)0x7C, (byte)0x26, (byte)0xB6, (byte)0xBE, (byte)0xA5, 
                        (byte)0x90, (byte)0xBC, (byte)0xBC, (byte)0xD1, (byte)0x2C, (byte)0xF8, 
                        (byte)0x7B, (byte)0x11, (byte)0x6E, (byte)0x87, (byte)0xD4, (byte)0x97, 
                        (byte)0x04, (byte)0x96, (byte)0xA5, (byte)0x2E, (byte)0x11};
              byte[] decrypted = cipher.doFinal(encrypted);
    On my card, it is a RSA_CRT algorithm, does that creat any problem?
    I add a 0x00 at the beggening of the modulus because otherwise, it makes a 511 bits key because it is negative or something, is it ok to do that? (It was a previous bug I had and got that solution from the forum BadPaddingException problem
    The key on my card should be a 2048 bits size key but my pubKey.tostring() tells me that.
    Sun RSA public key, 512 bits. Would that be normal?

    Thx for your help cheers!

    Edited by: FrancisOL on Mar 19, 2012 10:15 AM

    Edited by: sabre150 on Mar 19, 2012 5:20 PM

    Moderator action : added [ code] tags to make the code readable.
    1) You should use new BigInteger(1, modulus2) to force the value to be positive. No need to prefix with a zero byte. Check the Javadoc.

    2) If you have any doubt about the RSAPublic key generation then since RSAPublicKey is an interface you can implement it yourself. For decryption you only need to correctly implement the methods that get the modulus, exponent and the getAlgorithm() methods. The algorithm should return the string "RSA". When I do this I make the other methods throw some form of not implemented exception.

    3) I have never worked with RSA_CRT (I'm not sure what it is even - can you provide a reference?) but I know that
    Cipher cipher = Cipher.getInstance("RSA");
    is actually the same as
    Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
    so you will likely have a problem. To see if your result looks reasonable you can try with
    Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding");
    and then look to see if you can see your cleartext in the result (you do know your cleartext don't you?).

    4) Since you are decrypting with the public key I assume you are actually trying to verify a signature. Is that right?

    5) Your ciphertext and modulus are both 64 bytes long i.e.. 512 bits which means your RSA key pair is not 2048 bits but 512 bits !!!!!!!!!!

    Without access to the public key I can't help any further. If you want more help then post the modulus and exponent (since they are public there is no security problem) and a reference to CRT.


    Edited by: sabre150 on Mar 19, 2012 5:36 PM
  • 2. Re: javax.crypto.BadPaddingException: Data must start with zero
    918757 Newbie
    Currently Being Moderated
    Thx for your nice reply!

    Ok, I made the code that is in the card so I could do what's necessary to correct the key size. I maybe forgot to update my code because it was 512 bits before.

    I ecrypted that, 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF. And it is to verify a signature.

    I tried with the "RSA/ECB/NoPadding". Solved the error but it's not giving me the good answer. It gives me a 64 byte array size.

    The CRT thing concerns only the private key.
    http://docs.oracle.com/javase/1.4.2/docs/api/java/security/interfaces/RSAPrivateCrtKey.html

    in big integer, modulus is
    8369529596074756314657642338533610610556250671338223561908056795178145365660585786423627902433336372962635203031718013939994666126168800444328678682718929

    or if not parse into positive value,
    -5038278333867840784916382659672235516923115149254169815815504648543618664412961190378246395733567054727396655154768036913759216685777769502104970323365167

    So, would I need to convert the answer into some format to see if it fits the 00 11 22... bytes I encrypted?

    Edited by: FrancisOL on Mar 19, 2012 11:15 AM
  • 3. Re: javax.crypto.BadPaddingException: Data must start with zero
    sabre150 Expert
    Currently Being Moderated
    Sorry I can't help. The values you have posted are not consistent and you have not posted the public key exponent..
  • 4. Re: javax.crypto.BadPaddingException: Data must start with zero
    918757 Newbie
    Currently Being Moderated
    Ok, problem is fixed. I regenerated the key and it worked with the modification you suggested thx a lot!
  • 5. Re: javax.crypto.BadPaddingException: Data must start with zero
    sabre150 Expert
    Currently Being Moderated
    FrancisOL wrote:
    Ok, problem is fixed. I regenerated the key and it worked with the modification you suggested thx a lot!
    Err ... I hope you mean the suggestion that you use a different constructor for BigInteger and not the diagnostic change to using no padding!
  • 6. Re: javax.crypto.BadPaddingException: Data must start with zero
    918757 Newbie
    Currently Being Moderated
    Oh well, my bad there... tought i solved the problem but it's realy not the case...

    The public exponnent is 65537. How would you actualy get the data back?
  • 7. Re: javax.crypto.BadPaddingException: Data must start with zero
    safarmer Expert
    Currently Being Moderated
    Hi FrancisOL,

    Can you step through what you are doing to generate the signature as well as to verify? What it looks like is you have a key pair generated on your card and a hard coded block of data in your host application.

    Hopefully it is something like this:
    1. Generate a key pair on the card
    2. Get the public key from the card and create a key object
    3. Pass some data to the card to sign with the private key you just generated
    4. Verify the response from the card with the public key

    From what you posted I think you could be doing (based on your code):
    1. Generate a key pair on the card
    2. Get the public key from the card and create a key object
    3. Verify a pre-calculated signature with the public key from the card.

    If this is the case then the RSA algorithm is working as intended as you need the public key from the key pair used in the original operation.

    Cheers,
    Shane
  • 8. Re: javax.crypto.BadPaddingException: Data must start with zero
    918757 Newbie
    Currently Being Moderated
    ALL right, so here's an example of what I've done.

    I made a function that get 2 parameters, the key string(exponent and modulus)
    and the signed hash string is separated in 4 parts, 4 16 bytes array signed by the card.

    Here is the code I use if it can help people. (It's not the final code, still a draft but it works)

    (Just so you know the format of the 2 strings)
    String Key = Key = "65537 160059852537583614672804740864642092709...
    String SignedHash = "e2 29 e4 17 7a ad 90 4c 50 cd 8c 0e d9 74 4a 8b 43 ...

    public boolean process (String Key, String SignedHash){
              String a1 = "";
              String a2 = "";
              String a3 = "";
              String a4 = "";
              Key pubKey = null;
              String exponent = Key.substring(0, Key.indexOf(" "));
              String modulus = Key.substring(Key.indexOf(" ")+1);          
              
              BigInteger modulusKey = new BigInteger(modulus);
              BigInteger exponentKey = new BigInteger(exponent);
              
              RSAPublicKeySpec spec = new RSAPublicKeySpec(modulusKey, exponentKey);
              KeyFactory kf = null;
              try {
                   kf = KeyFactory.getInstance("RSA");
              } catch (NoSuchAlgorithmException e1) {
                   // TODO Auto-generated catch block
                   e1.printStackTrace();
              }
              try {
                   pubKey = kf.generatePublic(spec);
              } catch (InvalidKeySpecException e) {
                   // TODO Auto-generated catch block
                   e.printStackTrace();
              }
              
              String[] hashSection = new String[4];
              
              
              for(int i = 0; i < ((SignedHash.length()+1)/3)/128 ; i++){
                   hashSection[i] = SignedHash.substring(i * 128*3, (i*128*3) + (128*3) - 1);
                   hashSection[i] = hashSection.replace(" ", "");
              }     
              byte[] hashbytes1 = hex2Byte(hashSection[0]);
              byte[] hashbytes2 = hex2Byte(hashSection[1]);
              byte[] hashbytes3 = hex2Byte(hashSection[2]);
              byte[] hashbytes4 = hex2Byte(hashSection[3]);
              
              Cipher cipher = null;
              try {
                   cipher = Cipher.getInstance("RSA/ECB/NoPadding");
                   cipher.init(Cipher.DECRYPT_MODE, pubKey);
                   
                   byte[] hashDecrypte1 = cipher.doFinal(hashbytes1);
                   byte[] hashDecrypte2 = cipher.doFinal(hashbytes2);
                   byte[] hashDecrypte3 = cipher.doFinal(hashbytes3);
                   byte[] hashDecrypte4 = cipher.doFinal(hashbytes4);
                   
                   a1 = byte2hex(hashDecrypte1);
                   a2 = byte2hex(hashDecrypte2);
                   a3 = byte2hex(hashDecrypte3);
                   a4 = byte2hex(hashDecrypte4);
                   
                   System.out.println(a1);
                   System.out.println(a2);
                   System.out.println(a3);
                   System.out.println(a4);
              }catch (Exception e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
              }                    
              return false;     
         }
         public byte[] hex2Byte(String str)
    {
    byte[] bytes = new byte[str.length() / 2];
    for (int i = 0; i < bytes.length; i++)
    {
    bytes[i] = (byte) Integer
    .parseInt(str.substring(2 * i, 2 * i + 2), 16);
    }
    return bytes;
    }     
         public String byte2hex(byte[] b)
    {
    // String Buffer can be used instead
    String hs = "";
    String stmp = "";
    for (int n = 0; n < b.length; n++)
    {
    stmp = (java.lang.Integer.toHexString(b[n] & 0XFF));

    if (stmp.length() == 1)
    {
    hs = hs + "0" + stmp;
    }
    else
    {
    hs = hs + stmp;
    }

    if (n < b.length - 1)
    {
    hs = hs + "";
    }
    }
    return hs;
    }



    the decrypted awnsers (a1,a2,a3,a4) looks like

    0001ffffffff....fffff0052f10d8bd5c1f383d1642a9c88f8f8e0

    as you can see, i can get my 16 bytes back after the 00 at the end.

    The rest of the work should be relativly easy to do.

    Edited by: FrancisOL on Mar 21, 2012 11:29 AM

    Edited by: FrancisOL on Mar 21, 2012 11:34 AM
  • 9. Re: javax.crypto.BadPaddingException: Data must start with zero
    safarmer Expert
    Currently Being Moderated
    Hi,

    It is handy to put code in &#123;code} tags
    FrancisOL wrote:
    ALL right, so here's an example of what I've done.

    I made a function that get 2 parameters, the key string(exponent and modulus)
    and the signed hash string is separated in 4 parts, 4 16 bytes array signed by the card.

    Here is the code I use if it can help people. (It's not the final code, still a draft but it works)

    (Just so you know the format of the 2 strings)
    String Key = Key = "65537 160059852537583614672804740864642092709...
    String SignedHash = "e2 29 e4 17 7a ad 90 4c 50 cd 8c 0e d9 74 4a 8b 43 ...
    public boolean process (String Key, String SignedHash){
              String a1 = "";
              String a2 = "";
              String a3 = "";
              String a4 = "";
              Key pubKey = null;
              String exponent = Key.substring(0, Key.indexOf(" "));
              String modulus = Key.substring(Key.indexOf(" ")+1);          
              
              BigInteger modulusKey = new BigInteger(modulus);
              BigInteger exponentKey = new BigInteger(exponent);
              
              RSAPublicKeySpec spec = new RSAPublicKeySpec(modulusKey, exponentKey);
              KeyFactory kf = null;
              try {
                   kf = KeyFactory.getInstance("RSA");
              } catch (NoSuchAlgorithmException e1) {
                   // TODO Auto-generated catch block
                   e1.printStackTrace();
              }
              try {
                   pubKey = kf.generatePublic(spec);
              } catch (InvalidKeySpecException e) {
                   // TODO Auto-generated catch block
                   e.printStackTrace();
              }
              
              String[] hashSection = new String[4];
              
              
              for(int i = 0; i < ((SignedHash.length()+1)/3)/128 ; i++){
                   hashSection[i] = SignedHash.substring(i * 128*3, (i*128*3) + (128*3) - 1);
                   hashSection[i] = hashSection.replace(" ", "");
              }     
              byte[] hashbytes1 = hex2Byte(hashSection[0]);
              byte[] hashbytes2 = hex2Byte(hashSection[1]);
              byte[] hashbytes3 = hex2Byte(hashSection[2]);
              byte[] hashbytes4 = hex2Byte(hashSection[3]);
              
              Cipher cipher = null;
              try {
                   cipher = Cipher.getInstance("RSA/ECB/NoPadding");
                   cipher.init(Cipher.DECRYPT_MODE, pubKey);
                   
                   byte[] hashDecrypte1 = cipher.doFinal(hashbytes1);
                   byte[] hashDecrypte2 = cipher.doFinal(hashbytes2);
                   byte[] hashDecrypte3 = cipher.doFinal(hashbytes3);
                   byte[] hashDecrypte4 = cipher.doFinal(hashbytes4);
                   
                   a1 = byte2hex(hashDecrypte1);
                   a2 = byte2hex(hashDecrypte2);
                   a3 = byte2hex(hashDecrypte3);
                   a4 = byte2hex(hashDecrypte4);
                   
                   System.out.println(a1);
                   System.out.println(a2);
                   System.out.println(a3);
                   System.out.println(a4);
              }catch (Exception e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
              }                    
              return false;     
         }
         public byte[] hex2Byte(String str)
    {
    byte[] bytes = new byte[str.length() / 2];
    for (int i = 0; i < bytes.length; i++)
    {
    bytes[i] = (byte) Integer
    .parseInt(str.substring(2 * i, 2 * i + 2), 16);
    }
    return bytes;
    }     
         public String byte2hex(byte[] b)
    {
    // String Buffer can be used instead
    String hs = "";
    String stmp = "";
    for (int n = 0; n < b.length; n++)
    {
    stmp = (java.lang.Integer.toHexString(b[n] & 0XFF));

    if (stmp.length() == 1)
    {
    hs = hs + "0" + stmp;
    }
    else
    {
    hs = hs + stmp;
    }

    if (n < b.length - 1)
    {
    hs = hs + "";
    }
    }
    return hs;
    }
    the decrypted awnsers (a1,a2,a3,a4) looks like
    
    0001ffffffff....fffff0052f10d8bd5c1f383d1642a9c88f8f8e0
    
    as you can see, i can get my 16 bytes back after the 00 at the end.
    A few points about this code. 64 bytes is the block size of the 512bit RSA operation so you could simplify this code a lot by just using the key and full input in one doFinal(...). Also, if the intent is to verify a signature, you can use a Signature object something like this:
    Signature sig = Signature.getInstance("SHA1withRSA"); // assuming SHA1 in your signature
    sig.initVerify(pubKey);
    sig.update(inputBytes);
    boolean valid = sig.verify(signatureBytes);
    Cheers,
    Shane
  • 10. Re: javax.crypto.BadPaddingException: Data must start with zero
    918757 Newbie
    Currently Being Moderated
    That's right, it's seriously more simple.

    Thx a lot for all your wise advices, and your time!

    Edited by: FrancisOL on Mar 21, 2012 2:26 PM

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points