1 /*
2  * Copyright (c) 2005, 2013, 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 /**
31  * A response APDU as defined in ISO/IEC 7816-4. It consists of a conditional
32  * body and a two byte trailer.
33  * This class does not attempt to verify that the APDU encodes a semantically
34  * valid response.
35  *
36  * <p>Instances of this class are immutable. Where data is passed in or out
37  * via byte arrays, defensive cloning is performed.
38  *
39  * @see CommandAPDU
40  * @see CardChannel#transmit CardChannel.transmit
41  *
42  * @since   1.6
43  * @author  Andreas Sterbenz
44  * @author  JSR 268 Expert Group
45  */
46 public final class ResponseAPDU implements java.io.Serializable {
47 
48     private static final long serialVersionUID = 6962744978375594225L;
49 
50     /** @serial */
51     private byte[] apdu;
52 
53     /**
54      * Constructs a ResponseAPDU from a byte array containing the complete
55      * APDU contents (conditional body and trailed).
56      *
57      * <p>Note that the byte array is cloned to protect against subsequent
58      * modification.
59      *
60      * @param apdu the complete response APDU
61      *
62      * @throws NullPointerException if apdu is null
63      * @throws IllegalArgumentException if apdu.length is less than 2
64      */
ResponseAPDU(byte[] apdu)65     public ResponseAPDU(byte[] apdu) {
66         apdu = apdu.clone();
67         check(apdu);
68         this.apdu = apdu;
69     }
70 
check(byte[] apdu)71     private static void check(byte[] apdu) {
72         if (apdu.length < 2) {
73             throw new IllegalArgumentException("apdu must be at least 2 bytes long");
74         }
75     }
76 
77     /**
78      * Returns the number of data bytes in the response body (Nr) or 0 if this
79      * APDU has no body. This call is equivalent to
80      * <code>getData().length</code>.
81      *
82      * @return the number of data bytes in the response body or 0 if this APDU
83      * has no body.
84      */
getNr()85     public int getNr() {
86         return apdu.length - 2;
87     }
88 
89     /**
90      * Returns a copy of the data bytes in the response body. If this APDU as
91      * no body, this method returns a byte array with a length of zero.
92      *
93      * @return a copy of the data bytes in the response body or the empty
94      *    byte array if this APDU has no body.
95      */
getData()96     public byte[] getData() {
97         byte[] data = new byte[apdu.length - 2];
98         System.arraycopy(apdu, 0, data, 0, data.length);
99         return data;
100     }
101 
102     /**
103      * Returns the value of the status byte SW1 as a value between 0 and 255.
104      *
105      * @return the value of the status byte SW1 as a value between 0 and 255.
106      */
getSW1()107     public int getSW1() {
108         return apdu[apdu.length - 2] & 0xff;
109     }
110 
111     /**
112      * Returns the value of the status byte SW2 as a value between 0 and 255.
113      *
114      * @return the value of the status byte SW2 as a value between 0 and 255.
115      */
getSW2()116     public int getSW2() {
117         return apdu[apdu.length - 1] & 0xff;
118     }
119 
120     /**
121      * Returns the value of the status bytes SW1 and SW2 as a single
122      * status word SW.
123      * It is defined as
124      * {@code (getSW1() << 8) | getSW2()}
125      *
126      * @return the value of the status word SW.
127      */
getSW()128     public int getSW() {
129         return (getSW1() << 8) | getSW2();
130     }
131 
132     /**
133      * Returns a copy of the bytes in this APDU.
134      *
135      * @return a copy of the bytes in this APDU.
136      */
getBytes()137     public byte[] getBytes() {
138         return apdu.clone();
139     }
140 
141     /**
142      * Returns a string representation of this response APDU.
143      *
144      * @return a String representation of this response APDU.
145      */
toString()146     public String toString() {
147         return "ResponseAPDU: " + apdu.length + " bytes, SW="
148             + Integer.toHexString(getSW());
149     }
150 
151     /**
152      * Compares the specified object with this response APDU for equality.
153      * Returns true if the given object is also a ResponseAPDU and its bytes are
154      * identical to the bytes in this ResponseAPDU.
155      *
156      * @param obj the object to be compared for equality with this response APDU
157      * @return true if the specified object is equal to this response APDU
158      */
equals(Object obj)159     public boolean equals(Object obj) {
160         if (this == obj) {
161             return true;
162         }
163         if (obj instanceof ResponseAPDU == false) {
164             return false;
165         }
166         ResponseAPDU other = (ResponseAPDU)obj;
167         return Arrays.equals(this.apdu, other.apdu);
168     }
169 
170     /**
171      * Returns the hash code value for this response APDU.
172      *
173      * @return the hash code value for this response APDU.
174      */
hashCode()175     public int hashCode() {
176         return Arrays.hashCode(apdu);
177     }
178 
readObject(java.io.ObjectInputStream in)179     private void readObject(java.io.ObjectInputStream in)
180             throws java.io.IOException, ClassNotFoundException {
181         apdu = (byte[])in.readUnshared();
182         check(apdu);
183     }
184 
185 }
186