PCSC4Java
0.2
Library PCSC for Java language.
|
00001 /* 00002 * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. 00003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 00004 * 00005 * This code is free software; you can redistribute it and/or modify it 00006 * under the terms of the GNU General Public License version 2 only, as 00007 * published by the Free Software Foundation. Oracle designates this 00008 * particular file as subject to the "Classpath" exception as provided 00009 * by Oracle in the LICENSE file that accompanied this code. 00010 * 00011 * This code is distributed in the hope that it will be useful, but WITHOUT 00012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 00014 * version 2 for more details (a copy is included in the LICENSE file that 00015 * accompanied this code). 00016 * 00017 * You should have received a copy of the GNU General Public License version 00018 * 2 along with this work; if not, write to the Free Software Foundation, 00019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 00020 * 00021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 00022 * or visit www.oracle.com if you need additional information or have any 00023 * questions. 00024 */ 00025 00026 package fr.redbilled.pcscforjava; 00027 00028 import java.util.Arrays; 00029 00030 import java.nio.ByteBuffer; 00031 00065 public final class CommandAPDU implements java.io.Serializable { 00066 00067 private static final long serialVersionUID = 398698301286670877L; 00068 00069 private static final int MAX_APDU_SIZE = 65544; 00070 00072 private byte[] apdu; 00073 00074 // value of nc 00075 private transient int nc; 00076 00077 // value of ne 00078 private transient int ne; 00079 00080 // index of start of data within the apdu array 00081 private transient int dataOffset; 00082 00096 public CommandAPDU(byte[] apdu) { 00097 this.apdu = apdu.clone(); 00098 parse(); 00099 } 00100 00120 public CommandAPDU(byte[] apdu, int apduOffset, int apduLength) { 00121 checkArrayBounds(apdu, apduOffset, apduLength); 00122 this.apdu = new byte[apduLength]; 00123 System.arraycopy(apdu, apduOffset, this.apdu, 0, apduLength); 00124 parse(); 00125 } 00126 00127 private void checkArrayBounds(byte[] b, int ofs, int len) { 00128 if ((ofs < 0) || (len < 0)) { 00129 throw new IllegalArgumentException 00130 ("Offset and length must not be negative"); 00131 } 00132 if (b == null) { 00133 if ((ofs != 0) && (len != 0)) { 00134 throw new IllegalArgumentException 00135 ("offset and length must be 0 if array is null"); 00136 } 00137 } else { 00138 if (ofs > b.length - len) { 00139 throw new IllegalArgumentException 00140 ("Offset plus length exceed array size"); 00141 } 00142 } 00143 } 00144 00161 public CommandAPDU(ByteBuffer apdu) { 00162 this.apdu = new byte[apdu.remaining()]; 00163 apdu.get(this.apdu); 00164 parse(); 00165 } 00166 00176 public CommandAPDU(int cla, int ins, int p1, int p2) { 00177 this(cla, ins, p1, p2, null, 0, 0, 0); 00178 } 00179 00195 public CommandAPDU(int cla, int ins, int p1, int p2, int ne) { 00196 this(cla, ins, p1, p2, null, 0, 0, ne); 00197 } 00198 00216 public CommandAPDU(int cla, int ins, int p1, int p2, byte[] data) { 00217 this(cla, ins, p1, p2, data, 0, arrayLength(data), 0); 00218 } 00219 00243 public CommandAPDU(int cla, int ins, int p1, int p2, byte[] data, 00244 int dataOffset, int dataLength) { 00245 this(cla, ins, p1, p2, data, dataOffset, dataLength, 0); 00246 } 00247 00268 public CommandAPDU(int cla, int ins, int p1, int p2, byte[] data, int ne) { 00269 this(cla, ins, p1, p2, data, 0, arrayLength(data), ne); 00270 } 00271 00272 private static int arrayLength(byte[] b) { 00273 return (b != null) ? b.length : 0; 00274 } 00275 00290 private void parse() { 00291 if (apdu.length < 4) { 00292 throw new IllegalArgumentException("apdu must be at least 4 bytes long"); 00293 } 00294 if (apdu.length == 4) { 00295 // case 1 00296 return; 00297 } 00298 int l1 = apdu[4] & 0xff; 00299 if (apdu.length == 5) { 00300 // case 2s 00301 this.ne = (l1 == 0) ? 256 : l1; 00302 return; 00303 } 00304 if (l1 != 0) { 00305 if (apdu.length == 4 + 1 + l1) { 00306 // case 3s 00307 this.nc = l1; 00308 this.dataOffset = 5; 00309 return; 00310 } else if (apdu.length == 4 + 2 + l1) { 00311 // case 4s 00312 this.nc = l1; 00313 this.dataOffset = 5; 00314 int l2 = apdu[apdu.length - 1] & 0xff; 00315 this.ne = (l2 == 0) ? 256 : l2; 00316 return; 00317 } else { 00318 throw new IllegalArgumentException 00319 ("Invalid APDU: length=" + apdu.length + ", b1=" + l1); 00320 } 00321 } 00322 if (apdu.length < 7) { 00323 throw new IllegalArgumentException 00324 ("Invalid APDU: length=" + apdu.length + ", b1=" + l1); 00325 } 00326 int l2 = ((apdu[5] & 0xff) << 8) | (apdu[6] & 0xff); 00327 if (apdu.length == 7) { 00328 // case 2e 00329 this.ne = (l2 == 0) ? 65536 : l2; 00330 return; 00331 } 00332 if (l2 == 0) { 00333 throw new IllegalArgumentException("Invalid APDU: length=" 00334 + apdu.length + ", b1=" + l1 + ", b2||b3=" + l2); 00335 } 00336 if (apdu.length == 4 + 3 + l2) { 00337 // case 3e 00338 this.nc = l2; 00339 this.dataOffset = 7; 00340 return; 00341 } else if (apdu.length == 4 + 5 + l2) { 00342 // case 4e 00343 this.nc = l2; 00344 this.dataOffset = 7; 00345 int leOfs = apdu.length - 2; 00346 int l3 = ((apdu[leOfs] & 0xff) << 8) | (apdu[leOfs + 1] & 0xff); 00347 this.ne = (l3 == 0) ? 65536 : l3; 00348 } else { 00349 throw new IllegalArgumentException("Invalid APDU: length=" 00350 + apdu.length + ", b1=" + l1 + ", b2||b3=" + l2); 00351 } 00352 } 00353 00381 public CommandAPDU(int cla, int ins, int p1, int p2, byte[] data, 00382 int dataOffset, int dataLength, int ne) { 00383 checkArrayBounds(data, dataOffset, dataLength); 00384 if (dataLength > 65535) { 00385 throw new IllegalArgumentException("dataLength is too large"); 00386 } 00387 if (ne < 0) { 00388 throw new IllegalArgumentException("ne must not be negative"); 00389 } 00390 if (ne > 65536) { 00391 throw new IllegalArgumentException("ne is too large"); 00392 } 00393 this.ne = ne; 00394 this.nc = dataLength; 00395 if (dataLength == 0) { 00396 if (ne == 0) { 00397 // case 1 00398 this.apdu = new byte[4]; 00399 setHeader(cla, ins, p1, p2); 00400 } else { 00401 // case 2s or 2e 00402 if (ne <= 256) { 00403 // case 2s 00404 // 256 is encoded as 0x00 00405 byte len = (ne != 256) ? (byte)ne : 0; 00406 this.apdu = new byte[5]; 00407 setHeader(cla, ins, p1, p2); 00408 this.apdu[4] = len; 00409 } else { 00410 // case 2e 00411 byte l1, l2; 00412 // 65536 is encoded as 0x00 0x00 00413 if (ne == 65536) { 00414 l1 = 0; 00415 l2 = 0; 00416 } else { 00417 l1 = (byte)(ne >> 8); 00418 l2 = (byte)ne; 00419 } 00420 this.apdu = new byte[7]; 00421 setHeader(cla, ins, p1, p2); 00422 this.apdu[5] = l1; 00423 this.apdu[6] = l2; 00424 } 00425 } 00426 } else { 00427 if (ne == 0) { 00428 // case 3s or 3e 00429 if (dataLength <= 255) { 00430 // case 3s 00431 apdu = new byte[4 + 1 + dataLength]; 00432 setHeader(cla, ins, p1, p2); 00433 apdu[4] = (byte)dataLength; 00434 this.dataOffset = 5; 00435 System.arraycopy(data, dataOffset, apdu, 5, dataLength); 00436 } else { 00437 // case 3e 00438 apdu = new byte[4 + 3 + dataLength]; 00439 setHeader(cla, ins, p1, p2); 00440 apdu[4] = 0; 00441 apdu[5] = (byte)(dataLength >> 8); 00442 apdu[6] = (byte)dataLength; 00443 this.dataOffset = 7; 00444 System.arraycopy(data, dataOffset, apdu, 7, dataLength); 00445 } 00446 } else { 00447 // case 4s or 4e 00448 if ((dataLength <= 255) && (ne <= 256)) { 00449 // case 4s 00450 apdu = new byte[4 + 2 + dataLength]; 00451 setHeader(cla, ins, p1, p2); 00452 apdu[4] = (byte)dataLength; 00453 this.dataOffset = 5; 00454 System.arraycopy(data, dataOffset, apdu, 5, dataLength); 00455 apdu[apdu.length - 1] = (ne != 256) ? (byte)ne : 0; 00456 } else { 00457 // case 4e 00458 apdu = new byte[4 + 5 + dataLength]; 00459 setHeader(cla, ins, p1, p2); 00460 apdu[4] = 0; 00461 apdu[5] = (byte)(dataLength >> 8); 00462 apdu[6] = (byte)dataLength; 00463 this.dataOffset = 7; 00464 System.arraycopy(data, dataOffset, apdu, 7, dataLength); 00465 if (ne != 65536) { 00466 int leOfs = apdu.length - 2; 00467 apdu[leOfs] = (byte)(ne >> 8); 00468 apdu[leOfs + 1] = (byte)ne; 00469 } // else le == 65536: no need to fill in, encoded as 0 00470 } 00471 } 00472 } 00473 } 00474 00475 private void setHeader(int cla, int ins, int p1, int p2) { 00476 apdu[0] = (byte)cla; 00477 apdu[1] = (byte)ins; 00478 apdu[2] = (byte)p1; 00479 apdu[3] = (byte)p2; 00480 } 00481 00487 public int getCLA() { 00488 return apdu[0] & 0xff; 00489 } 00490 00496 public int getINS() { 00497 return apdu[1] & 0xff; 00498 } 00499 00505 public int getP1() { 00506 return apdu[2] & 0xff; 00507 } 00508 00514 public int getP2() { 00515 return apdu[3] & 0xff; 00516 } 00517 00526 public int getNc() { 00527 return nc; 00528 } 00529 00537 public byte[] getData() { 00538 byte[] data = new byte[nc]; 00539 System.arraycopy(apdu, dataOffset, data, 0, nc); 00540 return data; 00541 } 00542 00549 public int getNe() { 00550 return ne; 00551 } 00552 00558 public byte[] getBytes() { 00559 return apdu.clone(); 00560 } 00561 00567 public String toString() { 00568 return "CommmandAPDU: " + apdu.length + " bytes, nc=" + nc + ", ne=" + ne; 00569 } 00570 00579 public boolean equals(Object obj) { 00580 if (this == obj) { 00581 return true; 00582 } 00583 if (obj instanceof CommandAPDU == false) { 00584 return false; 00585 } 00586 CommandAPDU other = (CommandAPDU)obj; 00587 return Arrays.equals(this.apdu, other.apdu); 00588 } 00589 00595 public int hashCode() { 00596 return Arrays.hashCode(apdu); 00597 } 00598 00599 private void readObject(java.io.ObjectInputStream in) 00600 throws java.io.IOException, ClassNotFoundException { 00601 apdu = (byte[])in.readUnshared(); 00602 // initialize transient fields 00603 parse(); 00604 } 00605 00606 }