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