简体   繁体   中英

Verifying a signed string in JavaCard return `0x6F00` status word

I wrote the below JavaCard program to Sign a 4 byte length data based on ALG_RSA_SHA_256_PKCS1 algorithm and also to verify this signature:

package fileSigner;

import javacard.framework.*;
import javacard.security.KeyPair;
import javacard.security.RSAPrivateKey;
import javacard.security.RSAPublicKey;
import javacard.security.Signature;

public class FileSigning extends Applet {

    //Proprietary Status Words
    private static final short SIGN_VERIFIED_SW = (short) 0x6701;
    private static final short SIGN_NOT_VERIFIED_SW = (short) 0x6702;

    //Proprietary Instructions
    private static final byte SIGN_INS = (byte) 0x00;
    private static final byte VERIFY_INS = (byte) 0x02;
    private static final byte RET_PUB_KEY_INS = (byte) 0x04;

    //Required Objects
    private static RSAPrivateKey privateKey;
    private static RSAPublicKey publicKey;
    private static KeyPair keyPair;
    private static Signature signature;

    public static void install(byte[] bArray, short bOffset, byte bLength) {
        new FileSigning();
    }

    protected FileSigning() {
        register();
        keyPair = new KeyPair(KeyPair.ALG_RSA, (short) 1024);
        keyPair.genKeyPair();
        publicKey = (RSAPublicKey) keyPair.getPublic();
        privateKey = (RSAPrivateKey) keyPair.getPrivate();
        signature = Signature.getInstance(Signature.ALG_RSA_SHA_256_PKCS1, false);
    }

    public void process(APDU apdu) {
        if (selectingApplet()) {
            return;
        }

        byte[] buffer = apdu.getBuffer();

        switch (buffer[ISO7816.OFFSET_INS]) {
            case SIGN_INS:
                signature.init(privateKey, Signature.MODE_SIGN);
                byte[] dataSignature = JCSystem.makeTransientByteArray((short) 128, JCSystem.CLEAR_ON_RESET);
                short signLen = signature.sign(buffer, ISO7816.OFFSET_CDATA, (byte) ISO7816.OFFSET_LC, dataSignature, (byte) 0);
                Util.arrayCopyNonAtomic(dataSignature, (short) 0, buffer, (short) 0, signLen);
                apdu.setOutgoingAndSend((short) 0, signLen);
                break;

            case VERIFY_INS:
                signature.init(privateKey, Signature.MODE_VERIFY);
                boolean isVerified = signature.verify(buffer, (short)ISO7816.OFFSET_CDATA, (short)0x80, buffer, (short)(ISO7816.OFFSET_CDATA + 0X80), (short)0X04);
                if (isVerified) {
                    ISOException.throwIt(SIGN_VERIFIED_SW);
                } else {
                    ISOException.throwIt(SIGN_NOT_VERIFIED_SW);
                }
                break;

            case RET_PUB_KEY_INS:
                break;

            default:
                ISOException.throwIt((short) ISO7816.SW_INS_NOT_SUPPORTED);
        }
    }
}

Well, It seems that it works fine for sign method.

For example in the follow I sign 11223344 :

C:\OpenSCTool:> OSC.exe -s 00a4040006010203040501 -s 000000000411223344
Using reader with a card: ACS CCID USB Reader 0
Sending: 00 A4 04 00 06 01 02 03 04 05 01
Received (SW1=0x90, SW2=0x00)
Sending: 00 00 00 00 04 11 22 33 44
Received (SW1=0x90, SW2=0x00):
7B EE DE 3E 16 D6 82 CF 67 53 CC AF 87 F3 4F 31 {..>....gS....O1
BB A6 66 B6 4E E3 F5 FD 0E 04 18 24 63 C1 98 D4 ..f.N......$c...
17 CC 56 DA A0 5F 78 4D A5 AE DF E4 A6 E0 35 B6 ..V.._xM......5.
F0 F3 59 45 1E 89 EE 02 69 15 8C 27 7B 10 94 02 ..YE....i..'{...
F1 C5 A4 1C F2 3C 1A 75 8A FC 89 4F 59 A4 D5 A0 .....<.u...OY...
84 C5 5E 70 F8 B7 80 10 3D D3 84 56 EC CB 1D 01 ..^p....=..V....
D2 F4 F0 F4 FD 91 5A 52 45 17 A7 08 9D 26 82 A7 ......ZRE....&..
E3 67 A6 2C D8 CC 7F 59 F1 98 4A 4F 5D 78 63 DD .g.,...Y..JO]xc.

But I have problems with the verify method!

In the below I tried to verify the above signature:

C:\OpenSCTool:> OSC.exe -s 00a4040006010203040501 -s 00020000847BEEDE3E16D682CF6
753CCAF87F34F31BBA666B64EE3F5FD0E04182463C198D417CC56DAA05F784DA5AEDFE4A6E035B6F
0F359451E89EE0269158C277B109402F1C5A41CF23C1A758AFC894F59A4D5A084C55E70F8B780103
DD38456ECCB1D01D2F4F0F4FD915A524517A7089D2682A7E367A62CD8CC7F59F1984A4F5D7863DD1
1223344
Using reader with a card: ACS CCID USB Reader 0
Sending: 00 A4 04 00 06 01 02 03 04 05 01
Received (SW1=0x90, SW2=0x00)
Sending: 00 02 00 00 84 7B EE DE 3E 16 D6 82 CF 67 53 CC AF 87 F3 4F 31 BB A6 66
 B6 4E E3 F5 FD 0E 04 18 24 63 C1 98 D4 17 CC 56 DA A0 5F 78 4D A5 AE DF E4 A6 E
0 35 B6 F0 F3 59 45 1E 89 EE 02 69 15 8C 27 7B 10 94 02 F1 C5 A4 1C F2 3C 1A 75
8A FC 89 4F 59 A4 D5 A0 84 C5 5E 70 F8 B7 80 10 3D D3 84 56 EC CB 1D 01 D2 F4 F0
 F4 FD 91 5A 52 45 17 A7 08 9D 26 82 A7 E3 67 A6 2C D8 CC 7F 59 F1 98 4A 4F 5D 7
8 63 DD 11 22 33 44
Received (SW1=0x6F, SW2=0x00)

Update1:

I was wrongly wrote

signature.init(privateKey, Signature.MODE_VERIFY);

instead of

signature.init(publicKey, Signature.MODE_VERIFY);

in the section of VERIFY_INS . So I correct it and now the output is as below:

C:\OpenSCTool:> OSC.exe -s 00a4040006010203040501 -s 000000000411223344
Using reader with a card: ACS CCID USB Reader 0
Sending: 00 A4 04 00 06 01 02 03 04 05 01
Received (SW1=0x90, SW2=0x00)
Sending: 00 00 00 00 04 11 22 33 44
Received (SW1=0x90, SW2=0x00):
73 87 1C 58 07 EB F5 55 42 E3 37 FC 84 3A CA 91 s..X...UB.7..:..
FB F4 4D AD 70 FC 43 84 C0 26 DC AE 03 47 28 F3 ..M.p.C..&...G(.
F6 77 6B 53 93 96 92 4B 66 C8 BA 05 0F 65 56 CE .wkS...Kf....eV.
0E 7A 56 DE 5A 9C FF 4C FB B5 82 33 81 22 BD BE .zV.Z..L...3."..
76 99 15 87 5D 9C 4C 5F 6A 75 38 99 A9 28 D6 45 v...].L_ju8..(.E
A5 F4 8C A2 AE 89 28 49 ED 72 14 FD 7E 3C 6A F4 ......(I.r..~<j.
EA C2 7C BD AB D3 B3 91 1C 24 E0 29 B4 9C 07 82 ..|......$.)....
32 B1 BF 00 A5 A0 82 48 C2 01 82 A1 90 5A 47 05 2......H.....ZG.

C:\OpenSCTool:> OSC.exe -s 00a4040006010203040501 -s 000200008473871C5807EBF5554
2E337FC843ACA91FBF44DAD70FC4384C026DCAE034728F3F6776B539396924B66C8BA050F6556CE0
E7A56DE5A9CFF4CFBB582338122BDBE769915875D9C4C5F6A753899A928D645A5F48CA2AE892849E
D7214FD7E3C6AF4EAC27CBDABD3B3911C24E029B49C078232B1BF00A5A08248C20182A1905A47051
1223344
Using reader with a card: ACS CCID USB Reader 0
Sending: 00 A4 04 00 06 01 02 03 04 05 01
Received (SW1=0x90, SW2=0x00)
Sending: 00 02 00 00 84 73 87 1C 58 07 EB F5 55 42 E3 37 FC 84 3A CA 91 FB F4 4D
 AD 70 FC 43 84 C0 26 DC AE 03 47 28 F3 F6 77 6B 53 93 96 92 4B 66 C8 BA 05 0F 6
5 56 CE 0E 7A 56 DE 5A 9C FF 4C FB B5 82 33 81 22 BD BE 76 99 15 87 5D 9C 4C 5F
6A 75 38 99 A9 28 D6 45 A5 F4 8C A2 AE 89 28 49 ED 72 14 FD 7E 3C 6A F4 EA C2 7C
 BD AB D3 B3 91 1C 24 E0 29 B4 9C 07 82 32 B1 BF 00 A5 A0 82 48 C2 01 82 A1 90 5
A 47 05 11 22 33 44
Received (SW1=0x67, SW2=0x02)

As you see above, the card couldn't verify the signature that it create itself.


Updata2:

Based on dear Mr Maarten's answer I added setIncomingAndReceive() method to my program as below:

public class FileSigning extends Applet {

    //Proprietary Status Words
    private static final short SIGN_VERIFIED_SW = (short) 0x6701;
    private static final short SIGN_NOT_VERIFIED_SW = (short) 0x6702;

    //Proprietary Instructions
    private static final byte SIGN_INS = (byte) 0x00;
    private static final byte VERIFY_INS = (byte) 0x02;
    private static final byte RET_PUB_KEY_INS = (byte) 0x04;

    //Required Objects
    private static RSAPrivateKey privateKey;
    private static RSAPublicKey publicKey;
    private static KeyPair keyPair;
    private static Signature signature;

    public static void install(byte[] bArray, short bOffset, byte bLength) {
        new FileSigning();
    }

    protected FileSigning() {
        register();
        keyPair = new KeyPair(KeyPair.ALG_RSA, (short) 1024);
        keyPair.genKeyPair();
        publicKey = (RSAPublicKey) keyPair.getPublic();
        privateKey = (RSAPrivateKey) keyPair.getPrivate();
        signature = Signature.getInstance(Signature.ALG_RSA_SHA_256_PKCS1, false);
    }

    public void process(APDU apdu) {
        if (selectingApplet()) {
            return;
        }

        byte[] buffer = apdu.getBuffer();
        byte[] incomingData = JCSystem.makeTransientByteArray((short) 256, JCSystem.CLEAR_ON_RESET);
        short bytesLeft;
        short readCount;
        short offSet = 0x00;

        switch (buffer[ISO7816.OFFSET_INS]) {
            case SIGN_INS:
                signature.init(privateKey, Signature.MODE_SIGN);

                bytesLeft = (short) (buffer[ISO7816.OFFSET_LC] & 0x00FF);
                readCount = apdu.setIncomingAndReceive();
                while (bytesLeft > 0) {
                    Util.arrayCopyNonAtomic(buffer, ISO7816.OFFSET_CDATA, incomingData, offSet, readCount);
                    bytesLeft -= readCount;
                    offSet += readCount;
                    readCount = apdu.receiveBytes(ISO7816.OFFSET_CDATA);
                }
                short signLen = signature.sign(buffer, ISO7816.OFFSET_CDATA, (byte) ISO7816.OFFSET_LC, incomingData, (byte) 0);
                Util.arrayCopyNonAtomic(incomingData, (short) 0, buffer, (short) 0, signLen);
                apdu.setOutgoingAndSend((short) 0, signLen);
                break;

            case VERIFY_INS:
                signature.init(publicKey, Signature.MODE_VERIFY);

                bytesLeft = (short) (buffer[ISO7816.OFFSET_LC] & 0x00FF);
                readCount = apdu.setIncomingAndReceive();
                while (bytesLeft > 0) {
                    Util.arrayCopyNonAtomic(buffer, ISO7816.OFFSET_CDATA, incomingData, offSet, readCount);
                    bytesLeft -= readCount;
                    offSet += readCount;
                    readCount = apdu.receiveBytes(ISO7816.OFFSET_CDATA);
                }

                boolean isVerified = signature.verify(incomingData, (short) 0, (short) 0x80, incomingData, (short) 0X80, (short) 0X04);
                if (isVerified) {
                    ISOException.throwIt(SIGN_VERIFIED_SW);
                } else {
                    ISOException.throwIt(SIGN_NOT_VERIFIED_SW);
                }
                break;

            case RET_PUB_KEY_INS:
                break;

            default:
                ISOException.throwIt((short) ISO7816.SW_INS_NOT_SUPPORTED);
        }
    }
}

Well, it seems that there is something wrong still:

C:\OpenSCTool:> OSC.exe -s 00a4040006010203040501 -s 000000000411223344
Using reader with a card: ACS CCID USB Reader 0
Sending: 00 A4 04 00 06 01 02 03 04 05 01
Received (SW1=0x90, SW2=0x00)
Sending: 00 00 00 00 04 11 22 33 44
Received (SW1=0x90, SW2=0x00):
75 08 A1 D0 D7 C6 9E 60 3E 78 F0 3A 6B 50 A0 D8 u......`>x.:kP..
80 2E F3 3E 29 2C 0E 13 15 DC 78 74 14 33 4D 36 ...>),....xt.3M6
7E 5E C5 65 67 92 A0 7E B4 0A A1 C0 DE F2 63 44 ~^.eg..~......cD
84 E3 20 CC 48 96 6E B2 28 9A 1B 07 53 ED 70 AF .. .H.n.(...S.p.
8E 01 24 E0 B9 80 89 98 ED B7 A0 BB 81 37 81 22 ..$..........7."
1C C8 54 A4 91 D0 8D 83 12 31 41 1A 56 76 23 D4 ..T......1A.Vv#.
09 5C BD 1E 75 A6 D8 3A 57 15 D8 5E B0 B9 B5 E7 .\..u..:W..^....
32 46 BE C5 A8 58 79 1B D4 C5 20 DD 48 D3 70 CB 2F...Xy... .H.p.

C:\OpenSCTool:> OSC.exe -s 00a4040006010203040501 -s 00020000847508A1D0D7C69E603
E78F03A6B50A0D8802EF33E292C0E1315DC787414334D367E5EC5656792A07EB40AA1C0DEF263448
4E320CC48966EB2289A1B0753ED70AF8E0124E0B9808998EDB7A0BB813781221CC854A491D08D831
231411A567623D4095CBD1E75A6D83A5715D85EB0B9B5E73246BEC5A858791BD4C520DD48D370CB1
1223344
Using reader with a card: ACS CCID USB Reader 0
Sending: 00 A4 04 00 06 01 02 03 04 05 01
Received (SW1=0x90, SW2=0x00)
Sending: 00 02 00 00 84 75 08 A1 D0 D7 C6 9E 60 3E 78 F0 3A 6B 50 A0 D8 80 2E F3
 3E 29 2C 0E 13 15 DC 78 74 14 33 4D 36 7E 5E C5 65 67 92 A0 7E B4 0A A1 C0 DE F
2 63 44 84 E3 20 CC 48 96 6E B2 28 9A 1B 07 53 ED 70 AF 8E 01 24 E0 B9 80 89 98
ED B7 A0 BB 81 37 81 22 1C C8 54 A4 91 D0 8D 83 12 31 41 1A 56 76 23 D4 09 5C BD
 1E 75 A6 D8 3A 57 15 D8 5E B0 B9 B5 E7 32 46 BE C5 A8 58 79 1B D4 C5 20 DD 48 D
3 70 CB 11 22 33 44
Received (SW1=0x67, SW2=0x02)

Your verify() arguments are probably swapped (given you have [128 bytes signature][4 bytes data] in the incomingData):

boolean isVerified = signature.verify(incomingData, (short)0x80, (short) 4, incomingData, (short)0, (short)0x80);

Your java card code needs some polishing, for example the dataSignature/incomingData buffers should be allocated only once in the constructor (and CLEAR_ON_DESELECT should suffice).

You are forgetting to call apdu.setIncomingAndSend() , so all data may not be in the buffer. For small data (4 bytes) it usually is, but for larger data (ie the one that includes the signature for verification, it isn't.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM