diff --git a/src/main/java/pro/javacard/gp/GPUtils.java b/src/main/java/pro/javacard/gp/GPUtils.java index b19a3c64..eaa055e2 100644 --- a/src/main/java/pro/javacard/gp/GPUtils.java +++ b/src/main/java/pro/javacard/gp/GPUtils.java @@ -30,6 +30,7 @@ import org.slf4j.Logger; import java.io.ByteArrayOutputStream; +import java.nio.ByteBuffer; import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; @@ -112,6 +113,17 @@ public static byte[] encodeLength(int len) { return bo.toByteArray(); } + // Encodes APDU LC value, which has either length of 1 byte or 3 bytes (for extended length APDUs) + // If LC is bigger than fits in one byte (255), LC must be encoded in three bytes + public static byte[] encodeLcLength(int lc) { + if(lc>255) { + byte[] lc_ba = ByteBuffer.allocate(4).putInt(lc).array(); + return Arrays.copyOfRange(lc_ba, 1, 4); + } + else + return new byte[]{(byte)lc}; + } + // Assumes the bignum length must be even static byte[] positive(byte[] bytes) { if (bytes[0] == 0 && bytes.length % 2 == 1) { diff --git a/src/main/java/pro/javacard/gp/SCP03Wrapper.java b/src/main/java/pro/javacard/gp/SCP03Wrapper.java index 5fd3343f..7a69e4b7 100644 --- a/src/main/java/pro/javacard/gp/SCP03Wrapper.java +++ b/src/main/java/pro/javacard/gp/SCP03Wrapper.java @@ -85,7 +85,7 @@ protected CommandAPDU wrap(CommandAPDU command) throws GPException { bo.write(command.getINS()); bo.write(command.getP1()); bo.write(command.getP2()); - bo.write(lc); + bo.write(GPUtils.encodeLcLength(lc)); bo.write(data); byte[] cmac_input = bo.toByteArray(); byte[] cmac = GPCrypto.scp03_mac(sessionKeys.getKeyFor(GPSessionKeyProvider.KeyPurpose.MAC), cmac_input, 128); @@ -94,21 +94,22 @@ protected CommandAPDU wrap(CommandAPDU command) throws GPException { // 8 bytes for actual mac cmd_mac = Arrays.copyOf(cmac, 8); } - // Construct new command - ByteArrayOutputStream na = new ByteArrayOutputStream(); - na.write(cla); // possibly fiddled - na.write(command.getINS()); - na.write(command.getP1()); - na.write(command.getP2()); - na.write(lc); - na.write(data); - if (mac) - na.write(cmd_mac); + // Constructing new a new command APDU ensures that the coding of LC and NE is correct; especially for Extend Length APDUs + CommandAPDU newAPDU = null; + + ByteArrayOutputStream newData = new ByteArrayOutputStream(); + newData.write(data); + if (mac) { + newData.write(cmd_mac); + } if (command.getNe() > 0) { - na.write(command.getNe()); + newAPDU = new CommandAPDU(cla, command.getINS(), command.getP1(), command.getP2(),newData.toByteArray(),command.getNe()); + } + else { + newAPDU = new CommandAPDU(cla, command.getINS(), command.getP1(), command.getP2(),newData.toByteArray()); } - byte[] new_apdu = na.toByteArray(); - return new CommandAPDU(new_apdu); + return newAPDU; + } catch (IOException e) { throw new RuntimeException("APDU wrapping failed", e); } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {