Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.smartcardio/share/classes/javax/smartcardio/CommandAPDU.java
41153 views
1
/*
2
* Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package javax.smartcardio;
27
28
import java.util.Arrays;
29
30
import java.nio.ByteBuffer;
31
32
/**
33
* A command APDU following the structure defined in ISO/IEC 7816-4.
34
* It consists of a four byte header and a conditional body of variable length.
35
* This class does not attempt to verify that the APDU encodes a semantically
36
* valid command.
37
*
38
* <p>Note that when the expected length of the response APDU is specified
39
* in the {@linkplain #CommandAPDU(int,int,int,int,int) constructors},
40
* the actual length (Ne) must be specified, not its
41
* encoded form (Le). Similarly, {@linkplain #getNe} returns the actual
42
* value Ne. In other words, a value of 0 means "no data in the response APDU"
43
* rather than "maximum length."
44
*
45
* <p>This class supports both the short and extended forms of length
46
* encoding for Ne and Nc. However, note that not all terminals and Smart Cards
47
* are capable of accepting APDUs that use the extended form.
48
*
49
* <p>For the header bytes CLA, INS, P1, and P2 the Java type <code>int</code>
50
* is used to represent the 8 bit unsigned values. In the constructors, only
51
* the 8 lowest bits of the <code>int</code> value specified by the application
52
* are significant. The accessor methods always return the byte as an unsigned
53
* value between 0 and 255.
54
*
55
* <p>Instances of this class are immutable. Where data is passed in or out
56
* via byte arrays, defensive cloning is performed.
57
*
58
* @see ResponseAPDU
59
* @see CardChannel#transmit CardChannel.transmit
60
*
61
* @since 1.6
62
* @author Andreas Sterbenz
63
* @author JSR 268 Expert Group
64
*/
65
public final class CommandAPDU implements java.io.Serializable {
66
67
private static final long serialVersionUID = 398698301286670877L;
68
69
private static final int MAX_APDU_SIZE = 65544;
70
71
/** @serial */
72
private byte[] apdu;
73
74
// value of nc
75
private transient int nc;
76
77
// value of ne
78
private transient int ne;
79
80
// index of start of data within the apdu array
81
private transient int dataOffset;
82
83
/**
84
* Constructs a CommandAPDU from a byte array containing the complete
85
* APDU contents (header and body).
86
*
87
* <p>Note that the apdu bytes are copied to protect against
88
* subsequent modification.
89
*
90
* @param apdu the complete command APDU
91
*
92
* @throws NullPointerException if apdu is null
93
* @throws IllegalArgumentException if apdu does not contain a valid
94
* command APDU
95
*/
96
public CommandAPDU(byte[] apdu) {
97
this.apdu = apdu.clone();
98
parse();
99
}
100
101
/**
102
* Constructs a CommandAPDU from a byte array containing the complete
103
* APDU contents (header and body). The APDU starts at the index
104
* <code>apduOffset</code> in the byte array and is <code>apduLength</code>
105
* bytes long.
106
*
107
* <p>Note that the apdu bytes are copied to protect against
108
* subsequent modification.
109
*
110
* @param apdu the complete command APDU
111
* @param apduOffset the offset in the byte array at which the apdu
112
* data begins
113
* @param apduLength the length of the APDU
114
*
115
* @throws NullPointerException if apdu is null
116
* @throws IllegalArgumentException if apduOffset or apduLength are
117
* negative or if apduOffset + apduLength are greater than apdu.length,
118
* or if the specified bytes are not a valid APDU
119
*/
120
public CommandAPDU(byte[] apdu, int apduOffset, int apduLength) {
121
checkArrayBounds(apdu, apduOffset, apduLength);
122
this.apdu = new byte[apduLength];
123
System.arraycopy(apdu, apduOffset, this.apdu, 0, apduLength);
124
parse();
125
}
126
127
private void checkArrayBounds(byte[] b, int ofs, int len) {
128
if ((ofs < 0) || (len < 0)) {
129
throw new IllegalArgumentException
130
("Offset and length must not be negative");
131
}
132
if (b == null) {
133
if ((ofs != 0) && (len != 0)) {
134
throw new IllegalArgumentException
135
("offset and length must be 0 if array is null");
136
}
137
} else {
138
if (ofs > b.length - len) {
139
throw new IllegalArgumentException
140
("Offset plus length exceed array size");
141
}
142
}
143
}
144
145
/**
146
* Creates a CommandAPDU from the ByteBuffer containing the complete APDU
147
* contents (header and body).
148
* The buffer's <code>position</code> must be set to the start of the APDU,
149
* its <code>limit</code> to the end of the APDU. Upon return, the buffer's
150
* <code>position</code> is equal to its limit; its limit remains unchanged.
151
*
152
* <p>Note that the data in the ByteBuffer is copied to protect against
153
* subsequent modification.
154
*
155
* @param apdu the ByteBuffer containing the complete APDU
156
*
157
* @throws NullPointerException if apdu is null
158
* @throws IllegalArgumentException if apdu does not contain a valid
159
* command APDU
160
*/
161
public CommandAPDU(ByteBuffer apdu) {
162
this.apdu = new byte[apdu.remaining()];
163
apdu.get(this.apdu);
164
parse();
165
}
166
167
/**
168
* Constructs a CommandAPDU from the four header bytes. This is case 1
169
* in ISO 7816, no command body.
170
*
171
* @param cla the class byte CLA
172
* @param ins the instruction byte INS
173
* @param p1 the parameter byte P1
174
* @param p2 the parameter byte P2
175
*/
176
public CommandAPDU(int cla, int ins, int p1, int p2) {
177
this(cla, ins, p1, p2, null, 0, 0, 0);
178
}
179
180
/**
181
* Constructs a CommandAPDU from the four header bytes and the expected
182
* response data length. This is case 2 in ISO 7816, empty command data
183
* field with Ne specified. If Ne is 0, the APDU is encoded as ISO 7816
184
* case 1.
185
*
186
* @param cla the class byte CLA
187
* @param ins the instruction byte INS
188
* @param p1 the parameter byte P1
189
* @param p2 the parameter byte P2
190
* @param ne the maximum number of expected data bytes in a response APDU
191
*
192
* @throws IllegalArgumentException if ne is negative or greater than
193
* 65536
194
*/
195
public CommandAPDU(int cla, int ins, int p1, int p2, int ne) {
196
this(cla, ins, p1, p2, null, 0, 0, ne);
197
}
198
199
/**
200
* Constructs a CommandAPDU from the four header bytes and command data.
201
* This is case 3 in ISO 7816, command data present and Ne absent. The
202
* value Nc is taken as data.length. If <code>data</code> is null or
203
* its length is 0, the APDU is encoded as ISO 7816 case 1.
204
*
205
* <p>Note that the data bytes are copied to protect against
206
* subsequent modification.
207
*
208
* @param cla the class byte CLA
209
* @param ins the instruction byte INS
210
* @param p1 the parameter byte P1
211
* @param p2 the parameter byte P2
212
* @param data the byte array containing the data bytes of the command body
213
*
214
* @throws IllegalArgumentException if data.length is greater than 65535
215
*/
216
public CommandAPDU(int cla, int ins, int p1, int p2, byte[] data) {
217
this(cla, ins, p1, p2, data, 0, arrayLength(data), 0);
218
}
219
220
/**
221
* Constructs a CommandAPDU from the four header bytes and command data.
222
* This is case 3 in ISO 7816, command data present and Ne absent. The
223
* value Nc is taken as dataLength. If <code>dataLength</code>
224
* is 0, the APDU is encoded as ISO 7816 case 1.
225
*
226
* <p>Note that the data bytes are copied to protect against
227
* subsequent modification.
228
*
229
* @param cla the class byte CLA
230
* @param ins the instruction byte INS
231
* @param p1 the parameter byte P1
232
* @param p2 the parameter byte P2
233
* @param data the byte array containing the data bytes of the command body
234
* @param dataOffset the offset in the byte array at which the data
235
* bytes of the command body begin
236
* @param dataLength the number of the data bytes in the command body
237
*
238
* @throws NullPointerException if data is null and dataLength is not 0
239
* @throws IllegalArgumentException if dataOffset or dataLength are
240
* negative or if dataOffset + dataLength are greater than data.length
241
* or if dataLength is greater than 65535
242
*/
243
public CommandAPDU(int cla, int ins, int p1, int p2, byte[] data,
244
int dataOffset, int dataLength) {
245
this(cla, ins, p1, p2, data, dataOffset, dataLength, 0);
246
}
247
248
/**
249
* Constructs a CommandAPDU from the four header bytes, command data,
250
* and expected response data length. This is case 4 in ISO 7816,
251
* command data and Ne present. The value Nc is taken as data.length
252
* if <code>data</code> is non-null and as 0 otherwise. If Ne or Nc
253
* are zero, the APDU is encoded as case 1, 2, or 3 per ISO 7816.
254
*
255
* <p>Note that the data bytes are copied to protect against
256
* subsequent modification.
257
*
258
* @param cla the class byte CLA
259
* @param ins the instruction byte INS
260
* @param p1 the parameter byte P1
261
* @param p2 the parameter byte P2
262
* @param data the byte array containing the data bytes of the command body
263
* @param ne the maximum number of expected data bytes in a response APDU
264
*
265
* @throws IllegalArgumentException if data.length is greater than 65535
266
* or if ne is negative or greater than 65536
267
*/
268
public CommandAPDU(int cla, int ins, int p1, int p2, byte[] data, int ne) {
269
this(cla, ins, p1, p2, data, 0, arrayLength(data), ne);
270
}
271
272
private static int arrayLength(byte[] b) {
273
return (b != null) ? b.length : 0;
274
}
275
276
/**
277
* Command APDU encoding options:
278
*
279
* case 1: |CLA|INS|P1 |P2 | len = 4
280
* case 2s: |CLA|INS|P1 |P2 |LE | len = 5
281
* case 3s: |CLA|INS|P1 |P2 |LC |...BODY...| len = 6..260
282
* case 4s: |CLA|INS|P1 |P2 |LC |...BODY...|LE | len = 7..261
283
* case 2e: |CLA|INS|P1 |P2 |00 |LE1|LE2| len = 7
284
* case 3e: |CLA|INS|P1 |P2 |00 |LC1|LC2|...BODY...| len = 8..65542
285
* case 4e: |CLA|INS|P1 |P2 |00 |LC1|LC2|...BODY...|LE1|LE2| len =10..65544
286
*
287
* LE, LE1, LE2 may be 0x00.
288
* LC must not be 0x00 and LC1|LC2 must not be 0x00|0x00
289
*/
290
private void parse() {
291
if (apdu.length < 4) {
292
throw new IllegalArgumentException("apdu must be at least 4 bytes long");
293
}
294
if (apdu.length == 4) {
295
// case 1
296
return;
297
}
298
int l1 = apdu[4] & 0xff;
299
if (apdu.length == 5) {
300
// case 2s
301
this.ne = (l1 == 0) ? 256 : l1;
302
return;
303
}
304
if (l1 != 0) {
305
if (apdu.length == 4 + 1 + l1) {
306
// case 3s
307
this.nc = l1;
308
this.dataOffset = 5;
309
return;
310
} else if (apdu.length == 4 + 2 + l1) {
311
// case 4s
312
this.nc = l1;
313
this.dataOffset = 5;
314
int l2 = apdu[apdu.length - 1] & 0xff;
315
this.ne = (l2 == 0) ? 256 : l2;
316
return;
317
} else {
318
throw new IllegalArgumentException
319
("Invalid APDU: length=" + apdu.length + ", b1=" + l1);
320
}
321
}
322
if (apdu.length < 7) {
323
throw new IllegalArgumentException
324
("Invalid APDU: length=" + apdu.length + ", b1=" + l1);
325
}
326
int l2 = ((apdu[5] & 0xff) << 8) | (apdu[6] & 0xff);
327
if (apdu.length == 7) {
328
// case 2e
329
this.ne = (l2 == 0) ? 65536 : l2;
330
return;
331
}
332
if (l2 == 0) {
333
throw new IllegalArgumentException("Invalid APDU: length="
334
+ apdu.length + ", b1=" + l1 + ", b2||b3=" + l2);
335
}
336
if (apdu.length == 4 + 3 + l2) {
337
// case 3e
338
this.nc = l2;
339
this.dataOffset = 7;
340
return;
341
} else if (apdu.length == 4 + 5 + l2) {
342
// case 4e
343
this.nc = l2;
344
this.dataOffset = 7;
345
int leOfs = apdu.length - 2;
346
int l3 = ((apdu[leOfs] & 0xff) << 8) | (apdu[leOfs + 1] & 0xff);
347
this.ne = (l3 == 0) ? 65536 : l3;
348
} else {
349
throw new IllegalArgumentException("Invalid APDU: length="
350
+ apdu.length + ", b1=" + l1 + ", b2||b3=" + l2);
351
}
352
}
353
354
/**
355
* Constructs a CommandAPDU from the four header bytes, command data,
356
* and expected response data length. This is case 4 in ISO 7816,
357
* command data and Le present. The value Nc is taken as
358
* <code>dataLength</code>.
359
* If Ne or Nc
360
* are zero, the APDU is encoded as case 1, 2, or 3 per ISO 7816.
361
*
362
* <p>Note that the data bytes are copied to protect against
363
* subsequent modification.
364
*
365
* @param cla the class byte CLA
366
* @param ins the instruction byte INS
367
* @param p1 the parameter byte P1
368
* @param p2 the parameter byte P2
369
* @param data the byte array containing the data bytes of the command body
370
* @param dataOffset the offset in the byte array at which the data
371
* bytes of the command body begin
372
* @param dataLength the number of the data bytes in the command body
373
* @param ne the maximum number of expected data bytes in a response APDU
374
*
375
* @throws NullPointerException if data is null and dataLength is not 0
376
* @throws IllegalArgumentException if dataOffset or dataLength are
377
* negative or if dataOffset + dataLength are greater than data.length,
378
* or if ne is negative or greater than 65536,
379
* or if dataLength is greater than 65535
380
*/
381
public CommandAPDU(int cla, int ins, int p1, int p2, byte[] data,
382
int dataOffset, int dataLength, int ne) {
383
checkArrayBounds(data, dataOffset, dataLength);
384
if (dataLength > 65535) {
385
throw new IllegalArgumentException("dataLength is too large");
386
}
387
if (ne < 0) {
388
throw new IllegalArgumentException("ne must not be negative");
389
}
390
if (ne > 65536) {
391
throw new IllegalArgumentException("ne is too large");
392
}
393
this.ne = ne;
394
this.nc = dataLength;
395
if (dataLength == 0) {
396
if (ne == 0) {
397
// case 1
398
this.apdu = new byte[4];
399
setHeader(cla, ins, p1, p2);
400
} else {
401
// case 2s or 2e
402
if (ne <= 256) {
403
// case 2s
404
// 256 is encoded as 0x00
405
byte len = (ne != 256) ? (byte)ne : 0;
406
this.apdu = new byte[5];
407
setHeader(cla, ins, p1, p2);
408
this.apdu[4] = len;
409
} else {
410
// case 2e
411
byte l1, l2;
412
// 65536 is encoded as 0x00 0x00
413
if (ne == 65536) {
414
l1 = 0;
415
l2 = 0;
416
} else {
417
l1 = (byte)(ne >> 8);
418
l2 = (byte)ne;
419
}
420
this.apdu = new byte[7];
421
setHeader(cla, ins, p1, p2);
422
this.apdu[5] = l1;
423
this.apdu[6] = l2;
424
}
425
}
426
} else {
427
if (ne == 0) {
428
// case 3s or 3e
429
if (dataLength <= 255) {
430
// case 3s
431
apdu = new byte[4 + 1 + dataLength];
432
setHeader(cla, ins, p1, p2);
433
apdu[4] = (byte)dataLength;
434
this.dataOffset = 5;
435
System.arraycopy(data, dataOffset, apdu, 5, dataLength);
436
} else {
437
// case 3e
438
apdu = new byte[4 + 3 + dataLength];
439
setHeader(cla, ins, p1, p2);
440
apdu[4] = 0;
441
apdu[5] = (byte)(dataLength >> 8);
442
apdu[6] = (byte)dataLength;
443
this.dataOffset = 7;
444
System.arraycopy(data, dataOffset, apdu, 7, dataLength);
445
}
446
} else {
447
// case 4s or 4e
448
if ((dataLength <= 255) && (ne <= 256)) {
449
// case 4s
450
apdu = new byte[4 + 2 + dataLength];
451
setHeader(cla, ins, p1, p2);
452
apdu[4] = (byte)dataLength;
453
this.dataOffset = 5;
454
System.arraycopy(data, dataOffset, apdu, 5, dataLength);
455
apdu[apdu.length - 1] = (ne != 256) ? (byte)ne : 0;
456
} else {
457
// case 4e
458
apdu = new byte[4 + 5 + dataLength];
459
setHeader(cla, ins, p1, p2);
460
apdu[4] = 0;
461
apdu[5] = (byte)(dataLength >> 8);
462
apdu[6] = (byte)dataLength;
463
this.dataOffset = 7;
464
System.arraycopy(data, dataOffset, apdu, 7, dataLength);
465
if (ne != 65536) {
466
int leOfs = apdu.length - 2;
467
apdu[leOfs] = (byte)(ne >> 8);
468
apdu[leOfs + 1] = (byte)ne;
469
} // else le == 65536: no need to fill in, encoded as 0
470
}
471
}
472
}
473
}
474
475
private void setHeader(int cla, int ins, int p1, int p2) {
476
apdu[0] = (byte)cla;
477
apdu[1] = (byte)ins;
478
apdu[2] = (byte)p1;
479
apdu[3] = (byte)p2;
480
}
481
482
/**
483
* Returns the value of the class byte CLA.
484
*
485
* @return the value of the class byte CLA.
486
*/
487
public int getCLA() {
488
return apdu[0] & 0xff;
489
}
490
491
/**
492
* Returns the value of the instruction byte INS.
493
*
494
* @return the value of the instruction byte INS.
495
*/
496
public int getINS() {
497
return apdu[1] & 0xff;
498
}
499
500
/**
501
* Returns the value of the parameter byte P1.
502
*
503
* @return the value of the parameter byte P1.
504
*/
505
public int getP1() {
506
return apdu[2] & 0xff;
507
}
508
509
/**
510
* Returns the value of the parameter byte P2.
511
*
512
* @return the value of the parameter byte P2.
513
*/
514
public int getP2() {
515
return apdu[3] & 0xff;
516
}
517
518
/**
519
* Returns the number of data bytes in the command body (Nc) or 0 if this
520
* APDU has no body. This call is equivalent to
521
* <code>getData().length</code>.
522
*
523
* @return the number of data bytes in the command body or 0 if this APDU
524
* has no body.
525
*/
526
public int getNc() {
527
return nc;
528
}
529
530
/**
531
* Returns a copy of the data bytes in the command body. If this APDU as
532
* no body, this method returns a byte array with length zero.
533
*
534
* @return a copy of the data bytes in the command body or the empty
535
* byte array if this APDU has no body.
536
*/
537
public byte[] getData() {
538
byte[] data = new byte[nc];
539
System.arraycopy(apdu, dataOffset, data, 0, nc);
540
return data;
541
}
542
543
/**
544
* Returns the maximum number of expected data bytes in a response
545
* APDU (Ne).
546
*
547
* @return the maximum number of expected data bytes in a response APDU.
548
*/
549
public int getNe() {
550
return ne;
551
}
552
553
/**
554
* Returns a copy of the bytes in this APDU.
555
*
556
* @return a copy of the bytes in this APDU.
557
*/
558
public byte[] getBytes() {
559
return apdu.clone();
560
}
561
562
/**
563
* Returns a string representation of this command APDU.
564
*
565
* @return a String representation of this command APDU.
566
*/
567
public String toString() {
568
return "CommmandAPDU: " + apdu.length + " bytes, nc=" + nc + ", ne=" + ne;
569
}
570
571
/**
572
* Compares the specified object with this command APDU for equality.
573
* Returns true if the given object is also a CommandAPDU and its bytes are
574
* identical to the bytes in this CommandAPDU.
575
*
576
* @param obj the object to be compared for equality with this command APDU
577
* @return true if the specified object is equal to this command APDU
578
*/
579
public boolean equals(Object obj) {
580
if (this == obj) {
581
return true;
582
}
583
if (obj instanceof CommandAPDU == false) {
584
return false;
585
}
586
CommandAPDU other = (CommandAPDU)obj;
587
return Arrays.equals(this.apdu, other.apdu);
588
}
589
590
/**
591
* Returns the hash code value for this command APDU.
592
*
593
* @return the hash code value for this command APDU.
594
*/
595
public int hashCode() {
596
return Arrays.hashCode(apdu);
597
}
598
599
private void readObject(java.io.ObjectInputStream in)
600
throws java.io.IOException, ClassNotFoundException {
601
apdu = (byte[])in.readUnshared();
602
// initialize transient fields
603
parse();
604
}
605
606
}
607
608