summaryrefslogtreecommitdiff
path: root/smcc/src/main/java/at/gv/egiz/smcc/util
diff options
context:
space:
mode:
Diffstat (limited to 'smcc/src/main/java/at/gv/egiz/smcc/util')
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/util/ISO7816Utils.java831
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/util/SMCCHelper.java38
-rw-r--r--smcc/src/main/java/at/gv/egiz/smcc/util/TransparentFileInputStream.java379
3 files changed, 677 insertions, 571 deletions
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/util/ISO7816Utils.java b/smcc/src/main/java/at/gv/egiz/smcc/util/ISO7816Utils.java
index 22a707c8..f35086b6 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/util/ISO7816Utils.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/util/ISO7816Utils.java
@@ -1,19 +1,19 @@
/*
-* Copyright 2008 Federal Chancellery Austria and
-* Graz University of Technology
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
+ * Copyright 2008 Federal Chancellery Austria and
+ * Graz University of Technology
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package at.gv.egiz.smcc.util;
import java.io.ByteArrayOutputStream;
@@ -34,374 +34,435 @@ import at.gv.egiz.smcc.VerifyAPDUSpec;
public class ISO7816Utils {
- /**
- * file control information templates
- */
- public static final byte TAG_FCP = 0x62;
- public static final byte TAG_FMD = 0x64;
- public static final byte TAG_FCI = 0x6f;
-
- /**
- * file control informatino bitmasks (SELECT P2)
- */
- public static final byte P2_FCI = 0x00;
- public static final byte P2_FCP = 0x04;
- public static final byte P2_FMD = 0x08;
- public static final byte P2_NORESP = 0x0c;
-
-
- public static TransparentFileInputStream openTransparentFileInputStream(
- final CardChannel channel, int maxSize) {
-
- TransparentFileInputStream file = new TransparentFileInputStream(maxSize) {
-
- @Override
- protected byte[] readBinary(int offset, int len) throws IOException {
-
- ResponseAPDU resp;
- try {
- resp = channel.transmit(new CommandAPDU(0x00, 0xB0,
- 0x7F & (offset >> 8), offset & 0xFF, len));
- } catch (CardException e) {
- throw new IOException(e);
- }
-
- Throwable cause;
- if (resp.getSW() == 0x9000) {
- return resp.getData();
- } else if (resp.getSW() == 0x6982) {
- cause = new SecurityStatusNotSatisfiedException();
- } else {
- cause = new SignatureCardException("Failed to read bytes (offset=" + offset + ",len="
- + len + ") SW=" + Integer.toHexString(resp.getSW()) + ".");
- }
- throw new IOException(cause);
-
- }
-
- };
-
- return file;
-
- }
-
- public static byte[] readTransparentFile(CardChannel channel, int maxSize)
- throws CardException, SignatureCardException {
-
- TransparentFileInputStream is = openTransparentFileInputStream(channel, maxSize);
-
- try {
-
- ByteArrayOutputStream os = new ByteArrayOutputStream();
-
- int len;
- for (byte[] b = new byte[256]; (len = is.read(b)) != -1;) {
- os.write(b, 0, len);
- }
-
- return os.toByteArray();
-
- } catch (IOException e) {
- Throwable cause = e.getCause();
- if (cause instanceof CardException) {
- throw (CardException) cause;
- }
- if (cause instanceof SignatureCardException) {
- throw (SignatureCardException) cause;
- }
- throw new SignatureCardException(e);
- }
-
- }
-
- public static byte[] readTransparentFileTLV(CardChannel channel, int maxSize,
- byte expectedType) throws CardException, SignatureCardException {
-
- TransparentFileInputStream is = openTransparentFileInputStream(channel,
- maxSize);
-
- return readTransparentFileTLV(is, expectedType);
-
- }
-
- public static byte[] readTransparentFileTLV(TransparentFileInputStream is,
- byte expectedType) throws CardException, SignatureCardException {
-
-
- try {
-
- is.mark(256);
-
- // check expected type
- int b = is.read();
- if (b == 0x00 || b == 0xFF) {
- return null;
- }
- if (b == -1 || expectedType != (0xFF & b)) {
- throw new SignatureCardException("Unexpected TLV type. Expected "
- + Integer.toHexString(expectedType) + " but was "
- + Integer.toHexString(b) + ".");
- }
-
- // get actual length
- int actualSize = 2;
- b = is.read();
- if (b == -1) {
- return null;
- } else if ((0x80 & b) > 0) {
- int octets = (0x0F & b);
- actualSize += octets;
- for (int i = 1; i <= octets; i++) {
- b = is.read();
- if (b == -1) {
- return null;
- }
- actualSize += (0xFF & b) << ((octets - i) * 8);
- }
- } else {
- actualSize += 0xFF & b;
- }
-
- // set limit to actual size and read into buffer
- is.reset();
- is.setLimit(actualSize);
- byte[] buf = new byte[actualSize];
- if (is.read(buf) == actualSize) {
- return buf;
- } else {
- return null;
- }
-
- } catch (IOException e) {
- Throwable cause = e.getCause();
- if (cause instanceof CardException) {
- throw (CardException) cause;
- }
- if (cause instanceof SignatureCardException) {
- throw (SignatureCardException) cause;
- }
- throw new SignatureCardException(e);
- }
-
- }
-
- public static int getLengthFromFCx(byte[] fcx) {
-
- int len = -1;
-
- if (fcx.length != 0 && (fcx[0] == (byte) 0x62 || fcx[0] == (byte) 0x6F)) {
- int pos = 2;
- while (pos < (fcx[1] - 2)) {
- switch (fcx[pos]) {
-
- case (byte) 0x80:
- case (byte) 0x81: {
- len = 0xFF & fcx[pos + 2];
- for (int i = 1; i < fcx[pos + 1]; i++) {
- len<<=8;
- len+=0xFF & fcx[pos + i + 2];
- }
- }
-
- default:
- pos += 0xFF & fcx[pos + 1] + 2;
- }
- }
- }
-
- return len;
-
- }
-
- public static byte[] readRecord(CardChannel channel, int record) throws CardException, SignatureCardException {
-
- ResponseAPDU resp = channel.transmit(
- new CommandAPDU(0x00, 0xB2, record, 0x04, 256));
- if (resp.getSW() == 0x9000) {
- return resp.getData();
- } else {
- throw new SignatureCardException("Failed to read records. SW="
- + Integer.toHexString(resp.getSW()));
- }
-
- }
-
- public static void formatPIN(int pinFormat, int pinJustification, byte[] fpin, byte[] mask, char[] pin) {
-
- boolean left = (pinJustification == VerifyAPDUSpec.PIN_JUSTIFICATION_LEFT);
-
- int j = (left) ? 0 : fpin.length - 1;
- int step = (left) ? 1 : - 1;
- switch (pinFormat) {
- case VerifyAPDUSpec.PIN_FORMAT_BINARY:
- if (fpin.length < pin.length) {
- throw new IllegalArgumentException();
- }
- for (int i = 0; i < pin.length; i++) {
- fpin[j] = (byte) Character.digit(pin[i], 10);
- mask[j] = (byte) 0xFF;
- j += step;
- }
- break;
-
- case VerifyAPDUSpec.PIN_FORMAT_BCD:
- if (fpin.length * 2 < pin.length) {
- throw new IllegalArgumentException();
- }
- for (int i = 0; i < pin.length; i++) {
- int digit = Character.digit(pin[i], 10);
- boolean h = (i % 2 == 0) ^ left;
- fpin[j] |= h ? digit : digit << 4 ;
- mask[j] |= h ? (byte) 0x0F : (byte) 0xF0;
- j += (i % 2) * step;
- }
- break;
-
- case VerifyAPDUSpec.PIN_FORMAT_ASCII:
- if (fpin.length < pin.length) {
- throw new IllegalArgumentException();
- }
- byte[] asciiPin = Charset.forName("ASCII").encode(CharBuffer.wrap(pin)).array();
- for (int i = 0; i < pin.length; i++) {
- fpin[j] = asciiPin[i];
- mask[j] = (byte) 0xFF;
- j += step;
- }
- break;
- }
-
- }
-
- public static void insertPIN(byte[] apdu, int pos, byte[] fpin, byte[] mask) {
- for (int i = 0; i < fpin.length; i++) {
- apdu[pos + i] &= ~mask[i];
- apdu[pos + i] |= fpin[i];
- }
- }
-
- public static void insertPINLength(byte[] apdu, int length, int lengthSize, int pos, int offset) {
-
- // use short (2 byte) to be able to shift the pin length
- // by the number of bits given by the pin length position
- short size = (short) (0x00FF & length);
- short sMask = (short) ((1 << lengthSize) - 1);
- // shift to the proper position
- int shift = 16 - lengthSize - (pos % 8);
- offset += (pos / 8) + 5;
- size <<= shift;
- sMask <<= shift;
- // insert upper byte
- apdu[offset] &= (0xFF & (~sMask >> 8));
- apdu[offset] |= (0xFF & (size >> 8));
- // insert lower byte
- apdu[offset + 1] &= (0xFF & ~sMask);
- apdu[offset + 1] |= (0xFF & size);
-
- }
-
- public static CommandAPDU createVerifyAPDU(VerifyAPDUSpec apduSpec, char[] pin) {
-
- // format pin
- int l = (apduSpec.getPinLength() > 0) ? apduSpec.getPinLength() : pin.length;
- byte[] fpin = new byte[l];
- byte[] mask = new byte[l];
- formatPIN(apduSpec.getPinFormat(), apduSpec.getPinJustification(), fpin, mask, pin);
-
- byte[] template = apduSpec.getApdu();
- byte[] apdu = new byte[Math.max(template.length, 5 + apduSpec.getPinPosition() + l)];
- System.arraycopy(template, 0, apdu, 0, template.length);
- if (template.length < 5) {
- apdu[4] = (byte) (apdu.length - 5);
- }
-
- // insert formated pin
- insertPIN(apdu, apduSpec.getPinPosition() + 5, fpin, mask);
-
- // insert pin length
- if (apduSpec.getPinLengthSize() != 0) {
- insertPINLength(apdu, pin.length, apduSpec.getPinLengthSize(), apduSpec.getPinLengthPos(), 0);
- }
-
- return new CommandAPDU(apdu);
-
- }
-
- public static CommandAPDU createChangeReferenceDataAPDU(
- ChangeReferenceDataAPDUSpec apduSpec, char[] oldPin, char[] newPin) {
-
- int lo = (apduSpec.getPinLength() > 0) ? apduSpec.getPinLength() : oldPin.length;
- int ln = (apduSpec.getPinLength() > 0) ? apduSpec.getPinLength() : newPin.length;
-
- // format old pin
- byte[] fpin = new byte[lo];
- byte[] mask = new byte[lo];
- formatPIN(apduSpec.getPinFormat(), apduSpec.getPinJustification(), fpin, mask, oldPin);
-
- byte[] template = apduSpec.getApdu();
- byte[] apdu = new byte[Math.max(template.length,
- 5 + apduSpec.getPinPosition()
- + Math.max(apduSpec.getPinInsertionOffsetOld() + lo,
- apduSpec.getPinInsertionOffsetNew() + ln))];
- System.arraycopy(template, 0, apdu, 0, template.length);
- if (template.length < 5) {
- apdu[4] = (byte) (apdu.length - 5);
- }
-
- // insert formated old pin
- insertPIN(apdu, apduSpec.getPinPosition() + apduSpec.getPinInsertionOffsetOld() + 5, fpin, mask);
-
- // insert pin length
- if (apduSpec.getPinLengthSize() != 0) {
- insertPINLength(apdu, oldPin.length, apduSpec.getPinLengthSize(),
- apduSpec.getPinLengthPos(), apduSpec.getPinInsertionOffsetOld());
- }
-
- // format new pin
- fpin = new byte[ln];
- mask = new byte[ln];
- formatPIN(apduSpec.getPinFormat(), apduSpec.getPinJustification(), fpin, mask, newPin);
-
- // insert formated new pin
- insertPIN(apdu, apduSpec.getPinPosition() + apduSpec.getPinInsertionOffsetNew() + 5, fpin, mask);
-
- // insert pin length
- if (apduSpec.getPinLengthSize() != 0) {
- insertPINLength(apdu, newPin.length, apduSpec.getPinLengthSize(),
- apduSpec.getPinLengthPos(), apduSpec.getPinInsertionOffsetNew());
- }
-
- return new CommandAPDU(apdu);
-
- }
-
- public static CommandAPDU createNewReferenceDataAPDU(
- NewReferenceDataAPDUSpec apduSpec, char[] newPin) {
-
- // format old pin
- int l = (apduSpec.getPinLength() > 0) ? apduSpec.getPinLength() : newPin.length;
- byte[] fpin = new byte[l];
- byte[] mask = new byte[l];
- formatPIN(apduSpec.getPinFormat(), apduSpec.getPinJustification(), fpin, mask, newPin);
-
- byte[] template = apduSpec.getApdu();
- byte[] apdu = new byte[Math.max(template.length, 5 + apduSpec.getPinPosition() + l)];
- System.arraycopy(template, 0, apdu, 0, template.length);
- if (template.length < 5) {
- apdu[4] = (byte) (apdu.length - 5);
- }
-
- // insert formated new pin
- insertPIN(apdu, apduSpec.getPinPosition() + apduSpec.getPinInsertionOffsetNew() + 5, fpin, mask);
-
- // insert pin length
- if (apduSpec.getPinLengthSize() != 0) {
- insertPINLength(apdu, newPin.length, apduSpec.getPinLengthSize(),
- apduSpec.getPinLengthPos(), apduSpec.getPinInsertionOffsetNew());
- }
-
- return new CommandAPDU(apdu);
-
- }
-
-
+ /**
+ * file control information templates
+ */
+ public static final byte TAG_FCP = 0x62;
+ public static final byte TAG_FMD = 0x64;
+ public static final byte TAG_FCI = 0x6f;
+
+ /**
+ * file control informatino bitmasks (SELECT P2)
+ */
+ public static final byte P2_FCI = 0x00;
+ public static final byte P2_FCP = 0x04;
+ public static final byte P2_FMD = 0x08;
+ public static final byte P2_NORESP = 0x0c;
+
+ public static TransparentFileInputStream openTransparentFileInputStream(
+ final CardChannel channel, int maxSize) {
+
+ // open stream with default chunkSize of 256
+ return openTransparentFileInputStream(channel, maxSize, 256);
+ }
+
+ public static TransparentFileInputStream openTransparentFileInputStream(
+ final CardChannel channel, int maxSize, int chunkSize) {
+
+ TransparentFileInputStream file = new TransparentFileInputStream(
+ maxSize, chunkSize) {
+
+ @Override
+ protected byte[] readBinary(int offset, int len) throws IOException {
+
+ ResponseAPDU resp;
+ try {
+ resp = channel.transmit(new CommandAPDU(0x00, 0xB0,
+ 0x7F & (offset >> 8), offset & 0xFF, len));
+ } catch (CardException e) {
+ throw new IOException(e);
+ }
+
+ // handle case: wrong number of bytes requested from card
+ // card indicates correct number of bytes available in SW2
+ if (resp.getSW1() == 0x6c) {
+
+ try {
+ resp = channel.transmit(new CommandAPDU(0x00, 0xB0,
+ 0x7F & (offset >> 8), offset & 0xFF, resp
+ .getSW2()));
+ } catch (CardException e) {
+
+ throw new IOException("Error reading bytes from card.",
+ e);
+ }
+ }
+
+ Throwable cause;
+ if (resp.getSW() == 0x9000) {
+ return resp.getData();
+ } else if (resp.getSW() == 0x6982) {
+ cause = new SecurityStatusNotSatisfiedException();
+ } else {
+ cause = new SignatureCardException(
+ "Failed to read bytes (offset=" + offset + ",len="
+ + len + ") SW="
+ + Integer.toHexString(resp.getSW()) + ".");
+ }
+ throw new IOException(cause);
+
+ }
+
+ };
+
+ return file;
+
+ }
+
+ private static byte[] readFromInputStream(TransparentFileInputStream is) throws CardException, SignatureCardException {
+
+ try {
+
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+
+ int len;
+ for (byte[] b = new byte[256]; (len = is.read(b)) != -1;) {
+ os.write(b, 0, len);
+ }
+
+ return os.toByteArray();
+
+ } catch (IOException e) {
+ Throwable cause = e.getCause();
+ if (cause instanceof CardException) {
+ throw (CardException) cause;
+ }
+ if (cause instanceof SignatureCardException) {
+ throw (SignatureCardException) cause;
+ }
+ throw new SignatureCardException(e);
+ }
+ }
+
+ public static byte[] readTransparentFile(CardChannel channel, int maxSize, int chunkSize)
+ throws CardException, SignatureCardException {
+
+ TransparentFileInputStream is = openTransparentFileInputStream(channel,
+ maxSize, chunkSize);
+
+ return readFromInputStream(is);
+ }
+
+ public static byte[] readTransparentFile(CardChannel channel, int maxSize)
+ throws CardException, SignatureCardException {
+
+ TransparentFileInputStream is = openTransparentFileInputStream(channel,
+ maxSize);
+
+ return readFromInputStream(is);
+ }
+
+ public static byte[] readTransparentFileTLV(CardChannel channel,
+ int maxSize, byte expectedType) throws CardException,
+ SignatureCardException {
+
+ TransparentFileInputStream is = openTransparentFileInputStream(channel,
+ maxSize);
+
+ return readTransparentFileTLV(is, expectedType);
+
+ }
+
+ public static byte[] readTransparentFileTLV(TransparentFileInputStream is,
+ byte expectedType) throws CardException, SignatureCardException {
+
+ try {
+
+ is.mark(256);
+
+ // check expected type
+ int b = is.read();
+ if (b == 0x00 || b == 0xFF) {
+ return null;
+ }
+ if (b == -1 || expectedType != (0xFF & b)) {
+ throw new SignatureCardException(
+ "Unexpected TLV type. Expected "
+ + Integer.toHexString(expectedType)
+ + " but was " + Integer.toHexString(b) + ".");
+ }
+
+ // get actual length
+ int actualSize = 2;
+ b = is.read();
+ if (b == -1) {
+ return null;
+ } else if ((0x80 & b) > 0) {
+ int octets = (0x0F & b);
+ actualSize += octets;
+ for (int i = 1; i <= octets; i++) {
+ b = is.read();
+ if (b == -1) {
+ return null;
+ }
+ actualSize += (0xFF & b) << ((octets - i) * 8);
+ }
+ } else {
+ actualSize += 0xFF & b;
+ }
+
+ // set limit to actual size and read into buffer
+ is.reset();
+ is.setLimit(actualSize);
+ byte[] buf = new byte[actualSize];
+ if (is.read(buf) == actualSize) {
+ return buf;
+ } else {
+ return null;
+ }
+
+ } catch (IOException e) {
+ Throwable cause = e.getCause();
+ if (cause instanceof CardException) {
+ throw (CardException) cause;
+ }
+ if (cause instanceof SignatureCardException) {
+ throw (SignatureCardException) cause;
+ }
+ throw new SignatureCardException(e);
+ }
+
+ }
+
+ public static int getLengthFromFCx(byte[] fcx) {
+
+ int len = -1;
+
+ if (fcx.length != 0 && (fcx[0] == (byte) 0x62 || fcx[0] == (byte) 0x6F)) {
+ int pos = 2;
+ while (pos < (fcx[1] - 2)) {
+ switch (fcx[pos]) {
+
+ case (byte) 0x80:
+ case (byte) 0x81: {
+ len = 0xFF & fcx[pos + 2];
+ for (int i = 1; i < fcx[pos + 1]; i++) {
+ len <<= 8;
+ len += 0xFF & fcx[pos + i + 2];
+ }
+ }
+
+ default:
+ pos += 0xFF & fcx[pos + 1] + 2;
+ }
+ }
+ }
+
+ return len;
+
+ }
+
+ public static byte[] readRecord(CardChannel channel, int record)
+ throws CardException, SignatureCardException {
+
+ ResponseAPDU resp = channel.transmit(new CommandAPDU(0x00, 0xB2,
+ record, 0x04, 256));
+ if (resp.getSW() == 0x9000) {
+ return resp.getData();
+ } else {
+ throw new SignatureCardException("Failed to read records. SW="
+ + Integer.toHexString(resp.getSW()));
+ }
+
+ }
+
+ public static void formatPIN(int pinFormat, int pinJustification,
+ byte[] fpin, byte[] mask, char[] pin) {
+
+ boolean left = (pinJustification == VerifyAPDUSpec.PIN_JUSTIFICATION_LEFT);
+
+ int j = (left) ? 0 : fpin.length - 1;
+ int step = (left) ? 1 : -1;
+ switch (pinFormat) {
+ case VerifyAPDUSpec.PIN_FORMAT_BINARY:
+ if (fpin.length < pin.length) {
+ throw new IllegalArgumentException();
+ }
+ for (int i = 0; i < pin.length; i++) {
+ fpin[j] = (byte) Character.digit(pin[i], 10);
+ mask[j] = (byte) 0xFF;
+ j += step;
+ }
+ break;
+
+ case VerifyAPDUSpec.PIN_FORMAT_BCD:
+ if (fpin.length * 2 < pin.length) {
+ throw new IllegalArgumentException();
+ }
+ for (int i = 0; i < pin.length; i++) {
+ int digit = Character.digit(pin[i], 10);
+ boolean h = (i % 2 == 0) ^ left;
+ fpin[j] |= h ? digit : digit << 4;
+ mask[j] |= h ? (byte) 0x0F : (byte) 0xF0;
+ j += (i % 2) * step;
+ }
+ break;
+
+ case VerifyAPDUSpec.PIN_FORMAT_ASCII:
+ if (fpin.length < pin.length) {
+ throw new IllegalArgumentException();
+ }
+ byte[] asciiPin = Charset.forName("ASCII").encode(
+ CharBuffer.wrap(pin)).array();
+ for (int i = 0; i < pin.length; i++) {
+ fpin[j] = asciiPin[i];
+ mask[j] = (byte) 0xFF;
+ j += step;
+ }
+ break;
+ }
+
+ }
+
+ public static void insertPIN(byte[] apdu, int pos, byte[] fpin, byte[] mask) {
+ for (int i = 0; i < fpin.length; i++) {
+ apdu[pos + i] &= ~mask[i];
+ apdu[pos + i] |= fpin[i];
+ }
+ }
+
+ public static void insertPINLength(byte[] apdu, int length, int lengthSize,
+ int pos, int offset) {
+
+ // use short (2 byte) to be able to shift the pin length
+ // by the number of bits given by the pin length position
+ short size = (short) (0x00FF & length);
+ short sMask = (short) ((1 << lengthSize) - 1);
+ // shift to the proper position
+ int shift = 16 - lengthSize - (pos % 8);
+ offset += (pos / 8) + 5;
+ size <<= shift;
+ sMask <<= shift;
+ // insert upper byte
+ apdu[offset] &= (0xFF & (~sMask >> 8));
+ apdu[offset] |= (0xFF & (size >> 8));
+ // insert lower byte
+ apdu[offset + 1] &= (0xFF & ~sMask);
+ apdu[offset + 1] |= (0xFF & size);
+
+ }
+
+ public static CommandAPDU createVerifyAPDU(VerifyAPDUSpec apduSpec,
+ char[] pin) {
+
+ // format pin
+ int l = (apduSpec.getPinLength() > 0) ? apduSpec.getPinLength()
+ : pin.length;
+ byte[] fpin = new byte[l];
+ byte[] mask = new byte[l];
+ formatPIN(apduSpec.getPinFormat(), apduSpec.getPinJustification(),
+ fpin, mask, pin);
+
+ byte[] template = apduSpec.getApdu();
+ byte[] apdu = new byte[Math.max(template.length, 5
+ + apduSpec.getPinPosition() + l)];
+ System.arraycopy(template, 0, apdu, 0, template.length);
+ if (template.length < 5) {
+ apdu[4] = (byte) (apdu.length - 5);
+ }
+
+ // insert formated pin
+ insertPIN(apdu, apduSpec.getPinPosition() + 5, fpin, mask);
+
+ // insert pin length
+ if (apduSpec.getPinLengthSize() != 0) {
+ insertPINLength(apdu, pin.length, apduSpec.getPinLengthSize(),
+ apduSpec.getPinLengthPos(), 0);
+ }
+
+ return new CommandAPDU(apdu);
+
+ }
+
+ public static CommandAPDU createChangeReferenceDataAPDU(
+ ChangeReferenceDataAPDUSpec apduSpec, char[] oldPin, char[] newPin) {
+
+ int lo = (apduSpec.getPinLength() > 0) ? apduSpec.getPinLength()
+ : oldPin.length;
+ int ln = (apduSpec.getPinLength() > 0) ? apduSpec.getPinLength()
+ : newPin.length;
+
+ // format old pin
+ byte[] fpin = new byte[lo];
+ byte[] mask = new byte[lo];
+ formatPIN(apduSpec.getPinFormat(), apduSpec.getPinJustification(),
+ fpin, mask, oldPin);
+
+ byte[] template = apduSpec.getApdu();
+ byte[] apdu = new byte[Math.max(template.length, 5
+ + apduSpec.getPinPosition()
+ + Math.max(apduSpec.getPinInsertionOffsetOld() + lo, apduSpec
+ .getPinInsertionOffsetNew()
+ + ln))];
+ System.arraycopy(template, 0, apdu, 0, template.length);
+ if (template.length < 5) {
+ apdu[4] = (byte) (apdu.length - 5);
+ }
+
+ // insert formated old pin
+ insertPIN(apdu, apduSpec.getPinPosition()
+ + apduSpec.getPinInsertionOffsetOld() + 5, fpin, mask);
+
+ // insert pin length
+ if (apduSpec.getPinLengthSize() != 0) {
+ insertPINLength(apdu, oldPin.length, apduSpec.getPinLengthSize(),
+ apduSpec.getPinLengthPos(), apduSpec
+ .getPinInsertionOffsetOld());
+ }
+
+ // format new pin
+ fpin = new byte[ln];
+ mask = new byte[ln];
+ formatPIN(apduSpec.getPinFormat(), apduSpec.getPinJustification(),
+ fpin, mask, newPin);
+
+ // insert formated new pin
+ insertPIN(apdu, apduSpec.getPinPosition()
+ + apduSpec.getPinInsertionOffsetNew() + 5, fpin, mask);
+
+ // insert pin length
+ if (apduSpec.getPinLengthSize() != 0) {
+ insertPINLength(apdu, newPin.length, apduSpec.getPinLengthSize(),
+ apduSpec.getPinLengthPos(), apduSpec
+ .getPinInsertionOffsetNew());
+ }
+
+ return new CommandAPDU(apdu);
+
+ }
+
+ public static CommandAPDU createNewReferenceDataAPDU(
+ NewReferenceDataAPDUSpec apduSpec, char[] newPin) {
+
+ // format old pin
+ int l = (apduSpec.getPinLength() > 0) ? apduSpec.getPinLength()
+ : newPin.length;
+ byte[] fpin = new byte[l];
+ byte[] mask = new byte[l];
+ formatPIN(apduSpec.getPinFormat(), apduSpec.getPinJustification(),
+ fpin, mask, newPin);
+
+ byte[] template = apduSpec.getApdu();
+ byte[] apdu = new byte[Math.max(template.length, 5
+ + apduSpec.getPinPosition() + l)];
+ System.arraycopy(template, 0, apdu, 0, template.length);
+ if (template.length < 5) {
+ apdu[4] = (byte) (apdu.length - 5);
+ }
+
+ // insert formated new pin
+ insertPIN(apdu, apduSpec.getPinPosition()
+ + apduSpec.getPinInsertionOffsetNew() + 5, fpin, mask);
+
+ // insert pin length
+ if (apduSpec.getPinLengthSize() != 0) {
+ insertPINLength(apdu, newPin.length, apduSpec.getPinLengthSize(),
+ apduSpec.getPinLengthPos(), apduSpec
+ .getPinInsertionOffsetNew());
+ }
+
+ return new CommandAPDU(apdu);
+
+ }
+
}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/util/SMCCHelper.java b/smcc/src/main/java/at/gv/egiz/smcc/util/SMCCHelper.java
index d9816746..fd58964d 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/util/SMCCHelper.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/util/SMCCHelper.java
@@ -16,10 +16,12 @@
*/
package at.gv.egiz.smcc.util;
+import java.math.BigInteger;
import java.util.Locale;
import java.util.Map;
import javax.smartcardio.Card;
+import javax.smartcardio.CardException;
import javax.smartcardio.CardTerminal;
import org.slf4j.Logger;
@@ -142,6 +144,42 @@ public class SMCCHelper {
return sb.toString();
}
+ public static byte[] toByteArray(int val) throws CardException {
+
+ String hexString = Integer.toHexString(val);
+
+ if (hexString.length() > 4) {
+ throw new CardException(
+ "Unexpected input length to toByteArray() utility method: "
+ + hexString.length());
+ }
+
+ byte high = 0x00;
+ byte low = 0x00;
+
+ if (hexString.length() <= 2) {
+
+ low = (byte) Integer.parseInt(hexString, 16);
+ } else {
+
+ low = (byte) Integer.parseInt(hexString.substring(hexString
+ .length() - 2), 16);
+ high = (byte) Integer.parseInt(hexString.substring(0, hexString
+ .length() - 2), 16);
+ }
+
+ return new byte[] { high, low };
+ }
+
+ public static BigInteger createUnsignedBigInteger(byte[] data) {
+
+ byte[] unsigned = new byte[data.length + 1];
+ unsigned[0] = (byte) 0x00;
+ System.arraycopy(data, 0, unsigned, 1, data.length);
+
+ return new BigInteger(unsigned);
+ }
+
public static boolean isUseSWCard() {
return useSWCard;
}
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/util/TransparentFileInputStream.java b/smcc/src/main/java/at/gv/egiz/smcc/util/TransparentFileInputStream.java
index 781f9137..2da17354 100644
--- a/smcc/src/main/java/at/gv/egiz/smcc/util/TransparentFileInputStream.java
+++ b/smcc/src/main/java/at/gv/egiz/smcc/util/TransparentFileInputStream.java
@@ -1,194 +1,201 @@
/*
-* Copyright 2008 Federal Chancellery Austria and
-* Graz University of Technology
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
+ * Copyright 2008 Federal Chancellery Austria and
+ * Graz University of Technology
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package at.gv.egiz.smcc.util;
import java.io.IOException;
import java.io.InputStream;
public abstract class TransparentFileInputStream extends InputStream {
-
- private final int chunkSize = 256;
-
- private byte[] buf = new byte[chunkSize];
- private int start = 0;
- private int end = 0;
-
- private int offset = 0;
-
- private int length = -1;
-
- private int limit = -1;
-
- private int mark = -1;
-
- private int readlimit = -1;
-
- public TransparentFileInputStream() {
- }
-
- public TransparentFileInputStream(int length) {
- this.length = length;
- }
-
- public void setLimit(int limit) {
- this.limit = limit;
- }
-
- private int fill() throws IOException {
- if (start == end && (limit < 0 || offset < limit)) {
- int l;
- if (limit > 0 && limit - offset < chunkSize) {
- l = limit - offset;
- } else if (length > 0) {
- if (length - offset < chunkSize) {
- l = length - offset;
- } else {
- l = chunkSize - 1;
- }
- } else {
- l = chunkSize;
- }
- byte[] b = readBinary(offset, l);
- offset += b.length;
- if (mark < 0) {
- start = 0;
- end = b.length;
- System.arraycopy(b, 0, buf, start, b.length);
- } else {
- if (end - mark + b.length > buf.length) {
- // double buffer size
- byte[] nbuf = new byte[buf.length * 2];
- System.arraycopy(buf, mark, nbuf, 0, end - mark);
- buf = nbuf;
- } else {
- System.arraycopy(buf, mark, buf, 0, end - mark);
- }
- start = start - mark;
- end = end - mark + b.length;
- mark = 0;
- System.arraycopy(b, 0, buf, start, b.length);
- }
- if (l > b.length) {
- // end of file reached
- setLimit(offset);
- }
- }
- return end - start;
- }
-
- protected abstract byte[] readBinary(int offset, int len) throws IOException;
-
- @Override
- public int read() throws IOException {
- int b = (fill() > 0) ? 0xFF & buf[start++] : -1;
- if (readlimit > 0 && start > readlimit) {
- mark = -1;
- readlimit = -1;
- }
- return b;
- }
-
- @Override
- public int read(byte[] b, int off, int len) throws IOException {
- if (b == null) {
- throw new NullPointerException();
- } else if (off < 0 || len < 0 || len > b.length - off) {
- throw new IndexOutOfBoundsException();
- } else if (len == 0) {
- return 0;
- }
-
- int count = 0;
- int l;
- while (count < len) {
- if (fill() > 0) {
- l = Math.min(end - start, len - count);
- System.arraycopy(buf, start, b, off, l);
- start += l;
- off += l;
- count += l;
- if (readlimit > 0 && start > readlimit) {
- mark = -1;
- readlimit = -1;
- }
- } else {
- return (count > 0) ? count : -1;
- }
- }
-
- return count;
-
- }
-
- @Override
- public synchronized void mark(int readlimit) {
- this.readlimit = readlimit;
- mark = start;
- }
-
- @Override
- public boolean markSupported() {
- return true;
- }
-
- @Override
- public synchronized void reset() throws IOException {
- if (mark < 0) {
- throw new IOException();
- } else {
- start = mark;
- }
- }
-
- @Override
- public long skip(long n) throws IOException {
-
- if (n <= 0) {
- return 0;
- }
-
- if (n <= end - start) {
- start += n;
- return n;
- } else {
-
- mark = -1;
-
- long remaining = n - (end - start);
- start = end;
-
- if (limit >= 0 && limit < offset + remaining) {
- remaining -= limit - offset;
- offset = limit;
- return n - remaining;
- }
-
- if (length >= 0 && length < offset + remaining) {
- remaining -= length - offset;
- offset = length;
- return n - remaining;
- }
-
- offset += remaining;
-
- return n;
-
- }
-
- }
-
+
+ // private final int chunkSize = 256;
+ private int chunkSize = 256;
+
+ private byte[] buf = new byte[chunkSize];
+ private int start = 0;
+ private int end = 0;
+
+ private int offset = 0;
+
+ private int length = -1;
+
+ private int limit = -1;
+
+ private int mark = -1;
+
+ private int readlimit = -1;
+
+ public TransparentFileInputStream() {
+ }
+
+ public TransparentFileInputStream(int length) {
+ this.length = length;
+ }
+
+ public TransparentFileInputStream(int length, int chunkSize) {
+ this.length = length;
+ this.chunkSize = chunkSize;
+ }
+
+ public void setLimit(int limit) {
+ this.limit = limit;
+ }
+
+ private int fill() throws IOException {
+ if (start == end && (limit < 0 || offset < limit)) {
+ int l;
+ if (limit > 0 && limit - offset < chunkSize) {
+ l = limit - offset;
+ } else if (length > 0) {
+ if (length - offset < chunkSize) {
+ l = length - offset;
+ } else {
+ l = chunkSize - 1;
+ }
+ } else {
+ l = chunkSize;
+ }
+ byte[] b = readBinary(offset, l);
+ offset += b.length;
+ if (mark < 0) {
+ start = 0;
+ end = b.length;
+ System.arraycopy(b, 0, buf, start, b.length);
+ } else {
+ if (end - mark + b.length > buf.length) {
+ // double buffer size
+ byte[] nbuf = new byte[buf.length * 2];
+ System.arraycopy(buf, mark, nbuf, 0, end - mark);
+ buf = nbuf;
+ } else {
+ System.arraycopy(buf, mark, buf, 0, end - mark);
+ }
+ start = start - mark;
+ end = end - mark + b.length;
+ mark = 0;
+ System.arraycopy(b, 0, buf, start, b.length);
+ }
+ if (l > b.length) {
+ // end of file reached
+ setLimit(offset);
+ }
+ }
+ return end - start;
+ }
+
+ protected abstract byte[] readBinary(int offset, int len)
+ throws IOException;
+
+ @Override
+ public int read() throws IOException {
+ int b = (fill() > 0) ? 0xFF & buf[start++] : -1;
+ if (readlimit > 0 && start > readlimit) {
+ mark = -1;
+ readlimit = -1;
+ }
+ return b;
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ if (b == null) {
+ throw new NullPointerException();
+ } else if (off < 0 || len < 0 || len > b.length - off) {
+ throw new IndexOutOfBoundsException();
+ } else if (len == 0) {
+ return 0;
+ }
+
+ int count = 0;
+ int l;
+ while (count < len) {
+ if (fill() > 0) {
+ l = Math.min(end - start, len - count);
+ System.arraycopy(buf, start, b, off, l);
+ start += l;
+ off += l;
+ count += l;
+ if (readlimit > 0 && start > readlimit) {
+ mark = -1;
+ readlimit = -1;
+ }
+ } else {
+ return (count > 0) ? count : -1;
+ }
+ }
+
+ return count;
+
+ }
+
+ @Override
+ public synchronized void mark(int readlimit) {
+ this.readlimit = readlimit;
+ mark = start;
+ }
+
+ @Override
+ public boolean markSupported() {
+ return true;
+ }
+
+ @Override
+ public synchronized void reset() throws IOException {
+ if (mark < 0) {
+ throw new IOException();
+ } else {
+ start = mark;
+ }
+ }
+
+ @Override
+ public long skip(long n) throws IOException {
+
+ if (n <= 0) {
+ return 0;
+ }
+
+ if (n <= end - start) {
+ start += n;
+ return n;
+ } else {
+
+ mark = -1;
+
+ long remaining = n - (end - start);
+ start = end;
+
+ if (limit >= 0 && limit < offset + remaining) {
+ remaining -= limit - offset;
+ offset = limit;
+ return n - remaining;
+ }
+
+ if (length >= 0 && length < offset + remaining) {
+ remaining -= length - offset;
+ offset = length;
+ return n - remaining;
+ }
+
+ offset += remaining;
+
+ return n;
+
+ }
+
+ }
+
}