diff options
Diffstat (limited to 'ready_se/google/keymint/KM200/Applet/src/com/android/javacard/keymaster/KMInteger.java')
-rw-r--r-- | ready_se/google/keymint/KM200/Applet/src/com/android/javacard/keymaster/KMInteger.java | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/ready_se/google/keymint/KM200/Applet/src/com/android/javacard/keymaster/KMInteger.java b/ready_se/google/keymint/KM200/Applet/src/com/android/javacard/keymaster/KMInteger.java new file mode 100644 index 0000000..b09de0f --- /dev/null +++ b/ready_se/google/keymint/KM200/Applet/src/com/android/javacard/keymaster/KMInteger.java @@ -0,0 +1,215 @@ +/* + * Copyright(C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.javacard.keymaster; + +import com.android.javacard.seprovider.KMException; +import javacard.framework.ISO7816; +import javacard.framework.ISOException; +import javacard.framework.Util; + +/** + * Represents 8 bit, 16 bit, 32 bit and 64 bit unsigned integer. It corresponds to CBOR uint type. + * struct{byte INTEGER_TYPE; short length; 4 or 8 bytes of value} + */ +public class KMInteger extends KMType { + + public static final byte UINT_32 = 4; + public static final byte UINT_64 = 8; + private static KMInteger prototype; + + protected KMInteger() {} + + private static KMInteger proto(short ptr) { + if (prototype == null) { + prototype = new KMInteger(); + } + KMType.instanceTable[KM_INTEGER_OFFSET] = ptr; + return prototype; + } + + // | TYPE(1) | LEN(2) | DATA(4 / 8) | + public static short exp() { + return KMType.exp(INTEGER_TYPE); + } + + // return an empty integer instance + public static short instance(short length) { + if ((length <= 0) || (length > 8)) { + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); + } + if (length > 4) { + length = UINT_64; + } else { + length = UINT_32; + } + return KMType.instance(INTEGER_TYPE, length); + } + + public static short instance(byte[] num, short srcOff, short length) { + if (length > 8) { + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); + } + if (length == 1) { + return uint_8(num[srcOff]); + } else if (length == 2) { + return uint_16(Util.getShort(num, srcOff)); + } else if (length == 4) { + return uint_32(num, srcOff); + } else { + return uint_64(num, srcOff); + } + } + + public static KMInteger cast(short ptr) { + byte[] heap = repository.getHeap(); + if (heap[ptr] != INTEGER_TYPE) { + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + } + if (Util.getShort(heap, (short) (ptr + 1)) == INVALID_VALUE) { + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + } + return proto(ptr); + } + + // create integer and copy byte value + public static short uint_8(byte num) { + short ptr = instance(UINT_32); + heap[(short) (ptr + TLV_HEADER_SIZE + 3)] = num; + return ptr; + } + + // create integer and copy short value + public static short uint_16(short num) { + short ptr = instance(UINT_32); + Util.setShort(heap, (short) (ptr + TLV_HEADER_SIZE + 2), num); + return ptr; + } + + // create integer and copy integer value + public static short uint_32(byte[] num, short offset) { + short ptr = instance(UINT_32); + Util.arrayCopy(num, offset, heap, (short) (ptr + TLV_HEADER_SIZE), UINT_32); + return ptr; + } + + // create integer and copy integer value + public static short uint_64(byte[] num, short offset) { + short ptr = instance(UINT_64); + Util.arrayCopy(num, offset, heap, (short) (ptr + TLV_HEADER_SIZE), UINT_64); + return ptr; + } + + public static short compare(short num1, short num2) { + short num1Buf = repository.alloc((short) 8); + short num2Buf = repository.alloc((short) 8); + Util.arrayFillNonAtomic(repository.getHeap(), num1Buf, (short) 8, (byte) 0); + Util.arrayFillNonAtomic(repository.getHeap(), num2Buf, (short) 8, (byte) 0); + short len = KMInteger.cast(num1).length(); + KMInteger.cast(num1).getValue(repository.getHeap(), (short) (num1Buf + (short) (8 - len)), len); + len = KMInteger.cast(num2).length(); + KMInteger.cast(num2).getValue(repository.getHeap(), (short) (num2Buf + (short) (8 - len)), len); + return KMInteger.unsignedByteArrayCompare( + repository.getHeap(), num1Buf, repository.getHeap(), num2Buf, (short) 8); + } + + public static byte unsignedByteArrayCompare( + byte[] a1, short offset1, byte[] a2, short offset2, short length) { + byte count = (byte) 0; + short val1 = (short) 0; + short val2 = (short) 0; + + for (; count < length; count++) { + val1 = (short) (a1[(short) (count + offset1)] & 0x00FF); + val2 = (short) (a2[(short) (count + offset2)] & 0x00FF); + + if (val1 < val2) { + return -1; + } + if (val1 > val2) { + return 1; + } + } + return 0; + } + + // Get the length of the integer + public short length() { + return Util.getShort(heap, (short) (getBaseOffset() + 1)); + } + + // Get the buffer pointer in which blob is contained. + public byte[] getBuffer() { + return heap; + } + + // Get the start of value + public short getStartOff() { + return (short) (getBaseOffset() + TLV_HEADER_SIZE); + } + + public void getValue(byte[] dest, short destOff, short length) { + if (length < length()) { + KMException.throwIt(KMError.UNKNOWN_ERROR); + } + if (length > length()) { + length = length(); + destOff += length; + } + Util.arrayCopyNonAtomic(heap, getStartOff(), dest, destOff, length); + } + + public void setValue(byte[] src, short srcOff) { + Util.arrayCopyNonAtomic(src, srcOff, heap, getStartOff(), length()); + } + + public short value(byte[] dest, short destOff) { + Util.arrayCopyNonAtomic(heap, getStartOff(), dest, destOff, length()); + return length(); + } + + public short toLittleEndian(byte[] dest, short destOff) { + short index = (short) (length() - 1); + while (index >= 0) { + dest[destOff++] = heap[(short) (instanceTable[KM_INTEGER_OFFSET] + TLV_HEADER_SIZE + index)]; + index--; + } + return length(); + } + + public short getShort() { + return Util.getShort(heap, (short) (getStartOff() + 2)); + } + + public short getSignificantShort() { + return Util.getShort(heap, getStartOff()); + } + + public byte getByte() { + return heap[(short) (getStartOff() + 3)]; + } + + public boolean isZero() { + if (getShort() == 0 && getSignificantShort() == 0) { + return true; + } + return false; + } + + protected short getBaseOffset() { + return instanceTable[KM_INTEGER_OFFSET]; + } +} |