summaryrefslogtreecommitdiff
path: root/libmincrypt
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
committerThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
commit4f6e8d7a00cbeda1e70cc15be9c4af1018bdad53 (patch)
tree54fd1b2695a591d2306d41264df67c53077b752c /libmincrypt
Initial Contribution
Diffstat (limited to 'libmincrypt')
-rw-r--r--libmincrypt/Android.mk11
-rw-r--r--libmincrypt/rsa.c198
-rw-r--r--libmincrypt/sha.c142
-rw-r--r--libmincrypt/tools/Android.mk21
-rw-r--r--libmincrypt/tools/DumpPublicKey.java130
-rw-r--r--libmincrypt/tools/DumpPublicKey.mf1
6 files changed, 503 insertions, 0 deletions
diff --git a/libmincrypt/Android.mk b/libmincrypt/Android.mk
new file mode 100644
index 000000000..e27ab036b
--- /dev/null
+++ b/libmincrypt/Android.mk
@@ -0,0 +1,11 @@
+# Copyright 2008 The Android Open Source Project
+#
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libmincrypt
+LOCAL_SRC_FILES := rsa.c sha.c
+include $(BUILD_STATIC_LIBRARY)
+
+# TODO: drop the hyphen once these are checked in
+include $(LOCAL_PATH)/tools/Android.mk
diff --git a/libmincrypt/rsa.c b/libmincrypt/rsa.c
new file mode 100644
index 000000000..d7124fb65
--- /dev/null
+++ b/libmincrypt/rsa.c
@@ -0,0 +1,198 @@
+/* rsa.c
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** * Neither the name of Google Inc. nor the names of its contributors may
+** be used to endorse or promote products derived from this software
+** without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+** EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mincrypt/rsa.h"
+#include "mincrypt/sha.h"
+
+/* a[] -= mod */
+static void subM(const RSAPublicKey *key, uint32_t *a) {
+ int64_t A = 0;
+ int i;
+ for (i = 0; i < key->len; ++i) {
+ A += (uint64_t)a[i] - key->n[i];
+ a[i] = (uint32_t)A;
+ A >>= 32;
+ }
+}
+
+/* return a[] >= mod */
+static int geM(const RSAPublicKey *key, const uint32_t *a) {
+ int i;
+ for (i = key->len; i;) {
+ --i;
+ if (a[i] < key->n[i]) return 0;
+ if (a[i] > key->n[i]) return 1;
+ }
+ return 1; /* equal */
+}
+
+/* montgomery c[] += a * b[] / R % mod */
+static void montMulAdd(const RSAPublicKey *key,
+ uint32_t* c,
+ const uint32_t a,
+ const uint32_t* b) {
+ uint64_t A = (uint64_t)a * b[0] + c[0];
+ uint32_t d0 = (uint32_t)A * key->n0inv;
+ uint64_t B = (uint64_t)d0 * key->n[0] + (uint32_t)A;
+ int i;
+
+ for (i = 1; i < key->len; ++i) {
+ A = (A >> 32) + (uint64_t)a * b[i] + c[i];
+ B = (B >> 32) + (uint64_t)d0 * key->n[i] + (uint32_t)A;
+ c[i - 1] = (uint32_t)B;
+ }
+
+ A = (A >> 32) + (B >> 32);
+
+ c[i - 1] = (uint32_t)A;
+
+ if (A >> 32) {
+ subM(key, c);
+ }
+}
+
+/* montgomery c[] = a[] * b[] / R % mod */
+static void montMul(const RSAPublicKey *key,
+ uint32_t* c,
+ const uint32_t* a,
+ const uint32_t* b) {
+ int i;
+ for (i = 0; i < key->len; ++i) {
+ c[i] = 0;
+ }
+ for (i = 0; i < key->len; ++i) {
+ montMulAdd(key, c, a[i], b);
+ }
+}
+
+/* In-place public exponentiation.
+** Input and output big-endian byte array in inout.
+*/
+static void modpow3(const RSAPublicKey *key,
+ uint8_t* inout) {
+ uint32_t a[RSANUMWORDS];
+ uint32_t aR[RSANUMWORDS];
+ uint32_t aaR[RSANUMWORDS];
+ uint32_t *aaa = aR; /* Re-use location. */
+ int i;
+
+ /* Convert from big endian byte array to little endian word array. */
+ for (i = 0; i < key->len; ++i) {
+ uint32_t tmp =
+ (inout[((key->len - 1 - i) * 4) + 0] << 24) |
+ (inout[((key->len - 1 - i) * 4) + 1] << 16) |
+ (inout[((key->len - 1 - i) * 4) + 2] << 8) |
+ (inout[((key->len - 1 - i) * 4) + 3] << 0);
+ a[i] = tmp;
+ }
+
+ montMul(key, aR, a, key->rr); /* aR = a * RR / R mod M */
+ montMul(key, aaR, aR, aR); /* aaR = aR * aR / R mod M */
+ montMul(key, aaa, aaR, a); /* aaa = aaR * a / R mod M */
+
+ /* Make sure aaa < mod; aaa is at most 1x mod too large. */
+ if (geM(key, aaa)) {
+ subM(key, aaa);
+ }
+
+ /* Convert to bigendian byte array */
+ for (i = key->len - 1; i >= 0; --i) {
+ uint32_t tmp = aaa[i];
+ *inout++ = tmp >> 24;
+ *inout++ = tmp >> 16;
+ *inout++ = tmp >> 8;
+ *inout++ = tmp >> 0;
+ }
+}
+
+/* Expected PKCS1.5 signature padding bytes, for a keytool RSA signature.
+** Has the 0-length optional parameter encoded in the ASN1 (as opposed to the
+** other flavor which omits the optional parameter entirely). This code does not
+** accept signatures without the optional parameter.
+*/
+static const uint8_t padding[RSANUMBYTES - SHA_DIGEST_SIZE] = {
+ 0x00,0x01,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,
+ 0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1a,0x05,0x00,
+ 0x04,0x14
+};
+
+/* Verify a 2048 bit RSA PKCS1.5 signature against an expected SHA-1 hash.
+** Returns 0 on failure, 1 on success.
+*/
+int RSA_verify(const RSAPublicKey *key,
+ const uint8_t *signature,
+ const int len,
+ const uint8_t *sha) {
+ uint8_t buf[RSANUMBYTES];
+ int i;
+
+ if (key->len != RSANUMWORDS) {
+ return 0; /* Wrong key passed in. */
+ }
+
+ if (len != sizeof(buf)) {
+ return 0; /* Wrong input length. */
+ }
+
+ for (i = 0; i < len; ++i) {
+ buf[i] = signature[i];
+ }
+
+ modpow3(key, buf);
+
+ /* Check pkcs1.5 padding bytes. */
+ for (i = 0; i < (int) sizeof(padding); ++i) {
+ if (buf[i] != padding[i]) {
+ return 0;
+ }
+ }
+
+ /* Check sha digest matches. */
+ for (; i < len; ++i) {
+ if (buf[i] != *sha++) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
diff --git a/libmincrypt/sha.c b/libmincrypt/sha.c
new file mode 100644
index 000000000..d6120dae3
--- /dev/null
+++ b/libmincrypt/sha.c
@@ -0,0 +1,142 @@
+/* sha.c
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** * Neither the name of Google Inc. nor the names of its contributors may
+** be used to endorse or promote products derived from this software
+** without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+** EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mincrypt/sha.h"
+
+#define rol(bits, value) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+static void SHA1_transform(SHA_CTX *ctx) {
+ uint32_t W[80];
+ uint32_t A, B, C, D, E;
+ uint8_t *p = ctx->buf;
+ int t;
+
+ for(t = 0; t < 16; ++t) {
+ uint32_t tmp = *p++ << 24;
+ tmp |= *p++ << 16;
+ tmp |= *p++ << 8;
+ tmp |= *p++;
+ W[t] = tmp;
+ }
+
+ for(; t < 80; t++) {
+ W[t] = rol(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
+ }
+
+ A = ctx->state[0];
+ B = ctx->state[1];
+ C = ctx->state[2];
+ D = ctx->state[3];
+ E = ctx->state[4];
+
+ for(t = 0; t < 80; t++) {
+ uint32_t tmp = rol(5,A) + E + W[t];
+
+ if (t < 20)
+ tmp += (D^(B&(C^D))) + 0x5A827999;
+ else if ( t < 40)
+ tmp += (B^C^D) + 0x6ED9EBA1;
+ else if ( t < 60)
+ tmp += ((B&C)|(D&(B|C))) + 0x8F1BBCDC;
+ else
+ tmp += (B^C^D) + 0xCA62C1D6;
+
+ E = D;
+ D = C;
+ C = rol(30,B);
+ B = A;
+ A = tmp;
+ }
+
+ ctx->state[0] += A;
+ ctx->state[1] += B;
+ ctx->state[2] += C;
+ ctx->state[3] += D;
+ ctx->state[4] += E;
+}
+
+void SHA_init(SHA_CTX *ctx) {
+ ctx->state[0] = 0x67452301;
+ ctx->state[1] = 0xEFCDAB89;
+ ctx->state[2] = 0x98BADCFE;
+ ctx->state[3] = 0x10325476;
+ ctx->state[4] = 0xC3D2E1F0;
+ ctx->count = 0;
+}
+
+void SHA_update(SHA_CTX *ctx, const void *data, int len) {
+ int i = ctx->count % sizeof(ctx->buf);
+ const uint8_t* p = (const uint8_t*)data;
+
+ ctx->count += len;
+
+ while (len--) {
+ ctx->buf[i++] = *p++;
+ if (i == sizeof(ctx->buf)) {
+ SHA1_transform(ctx);
+ i = 0;
+ }
+ }
+}
+const uint8_t *SHA_final(SHA_CTX *ctx) {
+ uint8_t *p = ctx->buf;
+ uint64_t cnt = ctx->count * 8;
+ int i;
+
+ SHA_update(ctx, (uint8_t*)"\x80", 1);
+ while ((ctx->count % sizeof(ctx->buf)) != (sizeof(ctx->buf) - 8)) {
+ SHA_update(ctx, (uint8_t*)"\0", 1);
+ }
+ for (i = 0; i < 8; ++i) {
+ uint8_t tmp = cnt >> ((7 - i) * 8);
+ SHA_update(ctx, &tmp, 1);
+ }
+
+ for (i = 0; i < 5; i++) {
+ uint32_t tmp = ctx->state[i];
+ *p++ = tmp >> 24;
+ *p++ = tmp >> 16;
+ *p++ = tmp >> 8;
+ *p++ = tmp >> 0;
+ }
+
+ return ctx->buf;
+}
+
+/* Convenience function */
+const uint8_t* SHA(const void *data, int len, uint8_t *digest) {
+ const uint8_t *p;
+ int i;
+ SHA_CTX ctx;
+ SHA_init(&ctx);
+ SHA_update(&ctx, data, len);
+ p = SHA_final(&ctx);
+ for (i = 0; i < SHA_DIGEST_SIZE; ++i) {
+ digest[i] = *p++;
+ }
+ return digest;
+}
diff --git a/libmincrypt/tools/Android.mk b/libmincrypt/tools/Android.mk
new file mode 100644
index 000000000..b61234a9e
--- /dev/null
+++ b/libmincrypt/tools/Android.mk
@@ -0,0 +1,21 @@
+# Copyright (C) 2008 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.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := dumpkey
+LOCAL_SRC_FILES := DumpPublicKey.java
+LOCAL_JAR_MANIFEST := DumpPublicKey.mf
+include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/libmincrypt/tools/DumpPublicKey.java b/libmincrypt/tools/DumpPublicKey.java
new file mode 100644
index 000000000..c9e7e4d19
--- /dev/null
+++ b/libmincrypt/tools/DumpPublicKey.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2008 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.dumpkey;
+
+import java.io.FileInputStream;
+import java.math.BigInteger;
+import java.security.cert.CertificateFactory;
+import java.security.cert.Certificate;
+import java.security.KeyStore;
+import java.security.Key;
+import java.security.PublicKey;
+import java.security.interfaces.RSAPublicKey;
+import sun.misc.BASE64Encoder;
+
+/**
+ * Command line tool to extract RSA public keys from X.509 certificates
+ * and output source code with data initializers for the keys.
+ * @hide
+ */
+class DumpPublicKey {
+ /**
+ * @param key to perform sanity checks on
+ * @throws Exception if the key has the wrong size or public exponent
+ */
+ static void check(RSAPublicKey key) throws Exception {
+ BigInteger pubexp = key.getPublicExponent();
+ BigInteger modulus = key.getModulus();
+
+ if (!pubexp.equals(BigInteger.valueOf(3)))
+ throw new Exception("Public exponent should be 3 but is " +
+ pubexp.toString(10) + ".");
+
+ if (modulus.bitLength() != 2048)
+ throw new Exception("Modulus should be 2048 bits long but is " +
+ modulus.bitLength() + " bits.");
+ }
+
+ /**
+ * @param key to output
+ * @return a C initializer representing this public key.
+ */
+ static String print(RSAPublicKey key) throws Exception {
+ check(key);
+
+ BigInteger N = key.getModulus();
+
+ StringBuilder result = new StringBuilder();
+
+ int nwords = N.bitLength() / 32; // # of 32 bit integers in modulus
+
+ result.append("{");
+ result.append(nwords);
+
+ BigInteger B = BigInteger.valueOf(0x100000000L); // 2^32
+ BigInteger N0inv = B.subtract(N.modInverse(B)); // -1 / N[0] mod 2^32
+
+ result.append(",0x");
+ result.append(N0inv.toString(16));
+
+ BigInteger R = BigInteger.valueOf(2).pow(N.bitLength());
+ BigInteger RR = R.multiply(R).mod(N); // 2^4096 mod N
+
+ // Write out modulus as little endian array of integers.
+ result.append(",{");
+ for (int i = 0; i < nwords; ++i) {
+ int n = N.mod(B).intValue();
+ result.append(n);
+
+ if (i != nwords - 1) {
+ result.append(",");
+ }
+
+ N = N.divide(B);
+ }
+ result.append("}");
+
+ // Write R^2 as little endian array of integers.
+ result.append(",{");
+ for (int i = 0; i < nwords; ++i) {
+ int rr = RR.mod(B).intValue();
+ result.append(rr);
+
+ if (i != nwords - 1) {
+ result.append(",");
+ }
+
+ RR = RR.divide(B);
+ }
+ result.append("}");
+
+ result.append("}");
+ return result.toString();
+ }
+
+ public static void main(String[] args) {
+ if (args.length < 1) {
+ System.err.println("Usage: DumpPublicKey certfile ... > source.c");
+ System.exit(1);
+ }
+ try {
+ for (int i = 0; i < args.length; i++) {
+ FileInputStream input = new FileInputStream(args[i]);
+ CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ Certificate cert = cf.generateCertificate(input);
+ RSAPublicKey key = (RSAPublicKey) (cert.getPublicKey());
+ check(key);
+ System.out.print(print(key));
+ System.out.println(i < args.length - 1 ? "," : "");
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+ System.exit(0);
+ }
+}
diff --git a/libmincrypt/tools/DumpPublicKey.mf b/libmincrypt/tools/DumpPublicKey.mf
new file mode 100644
index 000000000..7bb3bc88d
--- /dev/null
+++ b/libmincrypt/tools/DumpPublicKey.mf
@@ -0,0 +1 @@
+Main-Class: com.android.dumpkey.DumpPublicKey