1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.location.cts.asn1.base;
18 
19 import com.google.common.base.Preconditions;
20 import com.google.common.collect.ImmutableList;
21 
22 import java.math.BigInteger;
23 import java.util.Arrays;
24 
25 /**
26  * Basic algorithms for aligned PER encoding and decoding, ASN.1 X.691-0207.
27  *
28  */
29 public class PerAlignedUtils {
30 
31   public static final int ONE_K = 1024;
32   public static final int SIXTEEN_K = 16 * ONE_K;
33   public static final int SIXTYFOUR_K = 64 * ONE_K;
34 
35 
36   /**
37    * Encodes whole numbers up to 64K range according to X.691-0207, 10.5.
38    */
encodeSmallConstrainedWholeNumber(int value, int minimumValue, int maximumValue)39   public static BitStream encodeSmallConstrainedWholeNumber(int value,
40                                                             int minimumValue,
41                                                             int maximumValue) {
42     int normalizedValue = value - minimumValue;
43     // Note: range here means one less than in ASN.1 X.691-0207, 10.5.
44     int range = maximumValue - minimumValue;
45     return encodeNormalizedSmallConstrainedWholeNumber(normalizedValue, range);
46   }
47 
48   /**
49    * Encodes the difference between the actual value and the minimum allowed
50    * value, the {@code normalizedValue}, for whole numbers up to 64K range
51    * according to X.691-0207, 10.5.
52    *
53    * <p>Note: range here means one less than in ASN.1 X.691-0207, 10.5., i.e.
54    * here it is the difference between the maximum allowed value and the minimum
55    * allowed value.
56    */
encodeNormalizedSmallConstrainedWholeNumber( int normalizedValue, int range)57   public static BitStream encodeNormalizedSmallConstrainedWholeNumber(
58       int normalizedValue, int range) {
59     Preconditions.checkArgument(range < SIXTYFOUR_K, "range >= 64K");
60     Preconditions.checkArgument(normalizedValue >= 0,
61                                 "negative normalized value");
62     BitStream result = new BitStream();
63     if (range == 0) {
64       return result;
65     }
66     if (range < 128) {
67       result.appendLowBits(leastBitsToEncode((byte) range),
68                            (byte) normalizedValue);
69       return result;
70     }
71     if (range >= 255) {
72       result.setBeginByteAligned();
73     }
74     if (range < 256) {
75       result.appendByte((byte) (normalizedValue));
76       return result;
77     }
78     result.appendByte((byte) ((normalizedValue & 0xFF00) >>> 8));
79     result.appendByte((byte) (normalizedValue & 0x00FF));
80     return result;
81   }
82 
83   /**
84    * Decodes whole numbers up to 64K range according to X.691-0207, 10.5.
85    */
decodeSmallConstrainedWholeNumber(BitStreamReader reader, int minimumValue, int maximumValue)86   public static int decodeSmallConstrainedWholeNumber(BitStreamReader reader,
87                                                       int minimumValue,
88                                                       int maximumValue) {
89     // Note: range here means one less than in ASN.1 X.691-0207, 10.5.
90     int range = maximumValue - minimumValue;
91     int normalizedResult =
92         decodeNormalizedSmallConstrainedWholeNumber(reader, range);
93     return normalizedResult + minimumValue;
94   }
95 
96   /**
97    * Decodes the difference between the actual value and the minimum allowed
98    * value for whole numbers up to 64K range according to X.691-0207, 10.5.
99    *
100    * <p>Note: range here means one less than in ASN.1 X.691-0207, 10.5., i.e.
101    * here it is the difference between the maximum allowed value and the minimum
102    * allowed value.
103    */
decodeNormalizedSmallConstrainedWholeNumber( BitStreamReader reader, int range)104   public static int decodeNormalizedSmallConstrainedWholeNumber(
105       BitStreamReader reader, int range) {
106     if (range < 0) {
107       throw new IllegalArgumentException("range < 0");
108     }
109     if (range >= SIXTYFOUR_K) {
110       throw new IllegalArgumentException("range >= 64K");
111     }
112     if (range == 0) {
113       return 0;
114     }
115     if (range < 128) {
116       return reader.readLowBits(leastBitsToEncode((byte) range));
117     }
118     if (range >= 255) {
119       reader.spoolToByteBoundary();
120     }
121     if (range < 256) {
122       return (reader.readByte() & 0xFF);
123     }
124     return ((reader.readByte() & 0xFF) << 8)
125         + (reader.readByte() & 0xFF);
126   }
127 
leastBitsToEncode(byte value)128   private static int leastBitsToEncode(byte value) {
129     int unsignedByte = value & 0xFF;
130     for (int bits = 1; bits < 8; bits++) {
131       if (unsignedByte < (1 << bits)) {
132         return bits;
133       }
134     }
135     return 8;
136   }
137 
encodeNormallySmallWholeNumber(int value)138   public static Iterable<BitStream> encodeNormallySmallWholeNumber(int value) {
139     if (value < 64) {
140       BitStream result = new BitStream();
141       result.appendBit(false);
142       result.appendLowBits(6, (byte) value);
143       return ImmutableList.of(result);
144     }
145     throw new UnsupportedOperationException("normally small numbers >= 64 "
146                                             + "unimplemented");
147   }
148 
decodeNormallySmallWholeNumber(BitStreamReader reader)149   public static int decodeNormallySmallWholeNumber(BitStreamReader reader) {
150     if (reader.readBit()) {
151       throw new UnsupportedOperationException("normally small numbers >= 64 "
152                                               + "unimplemented");
153     }
154     return reader.readLowBits(6) & 0xFF;
155   }
156 
157   /**
158    * Encodes length determinant for a constrained length byte[] according to
159    * X.691-0207, 10.9.3.3 and up.
160    */
encodeConstrainedLengthOfBytes( byte[] bytes, int minimumLength, int maximumLength)161   public static Iterable<BitStream> encodeConstrainedLengthOfBytes(
162       byte[] bytes, int minimumLength, int maximumLength) {
163     if (maximumLength >= SIXTYFOUR_K) {
164       return encodeSemiConstrainedLengthOfBytes(bytes);
165     }
166 
167     BitStream lengthDeterminant = encodeSmallConstrainedWholeNumber(
168         bytes.length, minimumLength, maximumLength);
169     if (bytes.length == 0) {
170       return ImmutableList.of(lengthDeterminant);
171     }
172     BitStream value = new BitStream();
173     value.setBeginByteAligned();
174     for (byte aByte : bytes) {
175       value.appendByte(aByte);
176     }
177     return ImmutableList.of(lengthDeterminant, value);
178 
179   }
180 
181   /**
182    * Decodes a constrained length byte[] with length determinant according to
183    * X.691-0207, 10.9.3.3 and up.
184    */
decodeConstrainedLengthOfBytes( BitStreamReader reader, int minimumLength, int maximumLength)185   public static byte[] decodeConstrainedLengthOfBytes(
186       BitStreamReader reader, int minimumLength, int maximumLength) {
187     if (maximumLength >= SIXTYFOUR_K) {
188       return decodeSemiConstrainedLengthOfBytes(reader);
189     }
190     int length = decodeSmallConstrainedWholeNumber(
191         reader, minimumLength, maximumLength);
192     if (length == 0) {
193       return new byte[0];
194     }
195     byte[] result = new byte[length];
196     reader.spoolToByteBoundary();
197     for (int i = 0; i < length; i++) {
198       result[i] = reader.readByte();
199     }
200     return result;
201   }
202 
203   /**
204    * Encodes length determinant for a semi-constrained length byte[] according
205    * to X.691-0207, 10.9.3.5.
206    */
encodeSemiConstrainedLengthOfBytes( byte[] bytes)207   public static Iterable<BitStream> encodeSemiConstrainedLengthOfBytes(
208       byte[] bytes) {
209     int n = bytes.length;
210     if (n < SIXTEEN_K) {
211       BitStream result = encodeSemiConstrainedLength(n);
212       result.setBeginByteAligned();
213       for (byte b : bytes) {
214         result.appendByte(b);
215       }
216       return ImmutableList.of(result);
217     }
218     throw new UnsupportedOperationException("Arrays > 16K unimplemented.");
219   }
220   /**
221    * Encodes length determinant for a semi-constrained length byte[] according
222    * to X.691-0207, 10.9.3.5.
223    */
encodeUnconstrainedLengthOfBytes( byte[] bytes)224   public static Iterable<BitStream> encodeUnconstrainedLengthOfBytes(
225       byte[] bytes) {
226     // Length for unconsrtained and semiconstrained integers is encoded by the
227     // same rules.
228     return encodeSemiConstrainedLengthOfBytes(bytes);
229   }
230   /**
231    * Decodes length determinant for a semi-constrained length byte[] according
232    * to X.691-0207, 10.9.3.5.
233    */
decodeSemiConstrainedLengthOfBytes( BitStreamReader reader)234   public static byte[] decodeSemiConstrainedLengthOfBytes(
235       BitStreamReader reader) {
236     reader.spoolToByteBoundary();
237     int length = decodeSemiConstrainedLength(reader);
238     byte[] result = new byte[length];
239     for (int i = 0; i < length; i++) {
240       result[i] = reader.readByte();
241     }
242     return result;
243   }
244   /**
245    * Decodes length determinant for a semi-constrained length byte[] according
246    * to X.691-0207, 10.9.3.5.
247    */
decodeUnconstrainedLengthOfBytes( BitStreamReader reader)248   public static byte[] decodeUnconstrainedLengthOfBytes(
249       BitStreamReader reader) {
250     // Length for unconsrtained and semiconstrained integers is encoded by the
251     // same rules.
252     return decodeSemiConstrainedLengthOfBytes(reader);
253   }
254   /**
255    * Encodes non-negative numbers according to X.691-0207, 10.3.
256    */
encodeBigNonNegativeWholeNumber(BigInteger bigInteger)257   public static byte[] encodeBigNonNegativeWholeNumber(BigInteger bigInteger) {
258     byte[] twosComplement = bigInteger.toByteArray();
259     return twosComplement[0] == 0
260            ? Arrays.copyOfRange(twosComplement, 1, twosComplement.length)
261            : twosComplement;
262   }
263 
264   /**
265     * Decodes non-negative numbers according to X.691-0207, 10.3.
266     */
decodeBigNonNegativeWholeNumber(byte[] encoded)267    public static BigInteger decodeBigNonNegativeWholeNumber(byte[] encoded) {
268     return new BigInteger(1, encoded);
269   }
270 
271   /**
272    * Encodes length determinant according to X.691-0207, 10.9.3.6.
273    */
encodeSemiConstrainedLength(int value)274   public static BitStream encodeSemiConstrainedLength(int value) {
275     if (value <= 127) {
276       BitStream result = new BitStream();
277       result.setBeginByteAligned();
278       result.appendBit(false);
279       result.appendLowBits(7, (byte) value);
280       return result;
281     } else if (value < SIXTEEN_K) {
282       BitStream result = new BitStream();
283       result.setBeginByteAligned();
284       result.appendBit(true);
285       result.appendBit(false);
286       result.appendLowBits(6, (byte) (value >>> 8));
287       result.appendByte((byte) (value & 0xFF));
288       return result;
289     }
290     throw new UnsupportedOperationException("Length values > " +
291                                              SIXTEEN_K + "unimplemented");
292   }
293 
294   /**
295    * Decodes length determinant according to X.691-0207, 10.9.3.6.
296    */
decodeSemiConstrainedLength(BitStreamReader reader)297   public static int decodeSemiConstrainedLength(BitStreamReader reader) {
298     reader.spoolToByteBoundary();
299     if (!reader.readBit()) {
300       return reader.readLowBits(7);
301     } else if (!reader.readBit()) {
302       return (reader.readLowBits(6) << 8) + (reader.readByte() & 0xFF);
303     } else {
304       throw new UnsupportedOperationException("Length values > " +
305                                                SIXTEEN_K + "unimplemented");
306     }
307   }
308 
309   /*
310    * Encodes an Asn1Object into a  Open type field (X.691-0207, 10.2), used
311    * mostly for encoding Sequence and SetOf extension additions. A decode method
312    * hasn't been added as the extension additions should decoded
313    * by their relevent Asn1Object decoders.
314    */
encodeOpenTypeField( Asn1Object object)315   public static Iterable<BitStream> encodeOpenTypeField(
316                                                     Asn1Object object){
317     PacketBuilder packetBuilder = new PacketBuilder();
318     packetBuilder.appendAll(object.encodePerAligned());
319     return encodeSemiConstrainedLengthOfBytes(packetBuilder.getPaddedBytes());
320   }
321 
decodeOpenTypeField( BitStreamReader reader, Asn1Object asn1Object)322   public static Asn1Object decodeOpenTypeField(
323                               BitStreamReader reader, Asn1Object asn1Object) {
324     byte [] encodedBytes = decodeSemiConstrainedLengthOfBytes(reader);
325     asn1Object.decodePerAligned(new BitStreamReader(encodedBytes));
326     return asn1Object;
327   }
328 }
329