Loading identity/java/android/security/identity/Util.java +39 −16 Original line number Original line Diff line number Diff line Loading @@ -20,12 +20,12 @@ import android.annotation.NonNull; import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.IOException; import java.math.BigInteger; import java.security.InvalidKeyException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; import java.security.PublicKey; import java.security.interfaces.ECPublicKey; import java.security.interfaces.ECPublicKey; import java.security.spec.ECPoint; import java.security.spec.ECPoint; import java.util.Collection; import javax.crypto.Mac; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import javax.crypto.spec.SecretKeySpec; Loading @@ -36,15 +36,6 @@ import javax.crypto.spec.SecretKeySpec; public class Util { public class Util { private static final String TAG = "Util"; private static final String TAG = "Util"; static int[] integerCollectionToArray(Collection<Integer> collection) { int[] result = new int[collection.size()]; int n = 0; for (int item : collection) { result[n++] = item; } return result; } static byte[] stripLeadingZeroes(byte[] value) { static byte[] stripLeadingZeroes(byte[] value) { int n = 0; int n = 0; while (n < value.length && value[n] == 0) { while (n < value.length && value[n] == 0) { Loading @@ -61,15 +52,47 @@ public class Util { static byte[] publicKeyEncodeUncompressedForm(PublicKey publicKey) { static byte[] publicKeyEncodeUncompressedForm(PublicKey publicKey) { ECPoint w = ((ECPublicKey) publicKey).getW(); ECPoint w = ((ECPublicKey) publicKey).getW(); // X and Y are always positive so for interop we remove any leading zeroes BigInteger x = w.getAffineX(); // inserted by the BigInteger encoder. BigInteger y = w.getAffineY(); byte[] x = stripLeadingZeroes(w.getAffineX().toByteArray()); if (x.compareTo(BigInteger.ZERO) < 0) { byte[] y = stripLeadingZeroes(w.getAffineY().toByteArray()); throw new RuntimeException("X is negative"); } if (y.compareTo(BigInteger.ZERO) < 0) { throw new RuntimeException("Y is negative"); } try { try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); baos.write(0x04); baos.write(0x04); baos.write(x); baos.write(y); // Each coordinate may be encoded in 33*, 32, or fewer bytes. // // * : it can be 33 bytes because toByteArray() guarantees "The array will contain the // minimum number of bytes required to represent this BigInteger, including at // least one sign bit, which is (ceil((this.bitLength() + 1)/8))" which means that // the MSB is always 0x00. This is taken care of by calling calling // stripLeadingZeroes(). // // We need the encoding to be exactly 32 bytes since according to RFC 5480 section 2.2 // and SEC 1: Elliptic Curve Cryptography section 2.3.3 the encoding is 0x04 | X | Y // where X and Y are encoded in exactly 32 byte, big endian integer values each. // byte[] xBytes = stripLeadingZeroes(x.toByteArray()); if (xBytes.length > 32) { throw new RuntimeException("xBytes is " + xBytes.length + " which is unexpected"); } for (int n = 0; n < 32 - xBytes.length; n++) { baos.write(0x00); } baos.write(xBytes); byte[] yBytes = stripLeadingZeroes(y.toByteArray()); if (yBytes.length > 32) { throw new RuntimeException("yBytes is " + yBytes.length + " which is unexpected"); } for (int n = 0; n < 32 - yBytes.length; n++) { baos.write(0x00); } baos.write(yBytes); return baos.toByteArray(); return baos.toByteArray(); } catch (IOException e) { } catch (IOException e) { throw new RuntimeException("Unexpected IOException", e); throw new RuntimeException("Unexpected IOException", e); Loading Loading
identity/java/android/security/identity/Util.java +39 −16 Original line number Original line Diff line number Diff line Loading @@ -20,12 +20,12 @@ import android.annotation.NonNull; import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.IOException; import java.math.BigInteger; import java.security.InvalidKeyException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; import java.security.PublicKey; import java.security.interfaces.ECPublicKey; import java.security.interfaces.ECPublicKey; import java.security.spec.ECPoint; import java.security.spec.ECPoint; import java.util.Collection; import javax.crypto.Mac; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import javax.crypto.spec.SecretKeySpec; Loading @@ -36,15 +36,6 @@ import javax.crypto.spec.SecretKeySpec; public class Util { public class Util { private static final String TAG = "Util"; private static final String TAG = "Util"; static int[] integerCollectionToArray(Collection<Integer> collection) { int[] result = new int[collection.size()]; int n = 0; for (int item : collection) { result[n++] = item; } return result; } static byte[] stripLeadingZeroes(byte[] value) { static byte[] stripLeadingZeroes(byte[] value) { int n = 0; int n = 0; while (n < value.length && value[n] == 0) { while (n < value.length && value[n] == 0) { Loading @@ -61,15 +52,47 @@ public class Util { static byte[] publicKeyEncodeUncompressedForm(PublicKey publicKey) { static byte[] publicKeyEncodeUncompressedForm(PublicKey publicKey) { ECPoint w = ((ECPublicKey) publicKey).getW(); ECPoint w = ((ECPublicKey) publicKey).getW(); // X and Y are always positive so for interop we remove any leading zeroes BigInteger x = w.getAffineX(); // inserted by the BigInteger encoder. BigInteger y = w.getAffineY(); byte[] x = stripLeadingZeroes(w.getAffineX().toByteArray()); if (x.compareTo(BigInteger.ZERO) < 0) { byte[] y = stripLeadingZeroes(w.getAffineY().toByteArray()); throw new RuntimeException("X is negative"); } if (y.compareTo(BigInteger.ZERO) < 0) { throw new RuntimeException("Y is negative"); } try { try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); baos.write(0x04); baos.write(0x04); baos.write(x); baos.write(y); // Each coordinate may be encoded in 33*, 32, or fewer bytes. // // * : it can be 33 bytes because toByteArray() guarantees "The array will contain the // minimum number of bytes required to represent this BigInteger, including at // least one sign bit, which is (ceil((this.bitLength() + 1)/8))" which means that // the MSB is always 0x00. This is taken care of by calling calling // stripLeadingZeroes(). // // We need the encoding to be exactly 32 bytes since according to RFC 5480 section 2.2 // and SEC 1: Elliptic Curve Cryptography section 2.3.3 the encoding is 0x04 | X | Y // where X and Y are encoded in exactly 32 byte, big endian integer values each. // byte[] xBytes = stripLeadingZeroes(x.toByteArray()); if (xBytes.length > 32) { throw new RuntimeException("xBytes is " + xBytes.length + " which is unexpected"); } for (int n = 0; n < 32 - xBytes.length; n++) { baos.write(0x00); } baos.write(xBytes); byte[] yBytes = stripLeadingZeroes(y.toByteArray()); if (yBytes.length > 32) { throw new RuntimeException("yBytes is " + yBytes.length + " which is unexpected"); } for (int n = 0; n < 32 - yBytes.length; n++) { baos.write(0x00); } baos.write(yBytes); return baos.toByteArray(); return baos.toByteArray(); } catch (IOException e) { } catch (IOException e) { throw new RuntimeException("Unexpected IOException", e); throw new RuntimeException("Unexpected IOException", e); Loading