summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDoug Zongker <dougz@android.com>2013-04-10 09:22:02 -0700
committerKenny Root <kroot@google.com>2013-09-25 09:26:34 -0700
commit8e5b63d045e988f13d1ee9b7797db28fde15bbfc (patch)
treeaaac24d144489aeeca8dcd002579e882445233a6
parent3c8bdef029cbaa8d8fa18e4e55e51b60e938dd6e (diff)
downloadsystem_core-8e5b63d045e988f13d1ee9b7797db28fde15bbfc.zip
system_core-8e5b63d045e988f13d1ee9b7797db28fde15bbfc.tar.gz
system_core-8e5b63d045e988f13d1ee9b7797db28fde15bbfc.tar.bz2
mincrypt: support SHA-256 hash algorithm
- adds a library to compute the SHA-256 hash - updates the RSA verifier to take an argument specifying either SHA-1 or SHA-256 - updates DumpPublicKey to with new "key" version numbers for specifying SHA-256 - adds new argument to adb auth code to maintain existing behavior (cherry picked from commit 515e1639ef0ab5e3149fafeffce826cf654d616f) Change-Id: Ib35643b3d864742e817ac6e725499b451e45afcf
-rw-r--r--adb/adb_auth_client.c3
-rw-r--r--include/mincrypt/hash-internal.h40
-rw-r--r--include/mincrypt/rsa.h3
-rw-r--r--include/mincrypt/sha.h65
-rw-r--r--include/mincrypt/sha256.h29
-rw-r--r--libmincrypt/Android.mk4
-rw-r--r--libmincrypt/rsa.c13
-rw-r--r--libmincrypt/rsa_e_3.c50
-rw-r--r--libmincrypt/rsa_e_f4.c79
-rw-r--r--libmincrypt/sha.c228
-rw-r--r--libmincrypt/sha256.c184
-rw-r--r--libmincrypt/tools/DumpPublicKey.java41
12 files changed, 468 insertions, 271 deletions
diff --git a/adb/adb_auth_client.c b/adb/adb_auth_client.c
index 763b448..f8d7306 100644
--- a/adb/adb_auth_client.c
+++ b/adb/adb_auth_client.c
@@ -25,6 +25,7 @@
#include "adb_auth.h"
#include "fdevent.h"
#include "mincrypt/rsa.h"
+#include "mincrypt/sha.h"
#define TRACE_TAG TRACE_AUTH
@@ -149,7 +150,7 @@ int adb_auth_verify(void *token, void *sig, int siglen)
list_for_each(item, &key_list) {
key = node_to_item(item, struct adb_public_key, node);
- ret = RSA_verify(&key->key, sig, siglen, token);
+ ret = RSA_verify(&key->key, sig, siglen, token, SHA_DIGEST_SIZE);
if (ret)
break;
}
diff --git a/include/mincrypt/hash-internal.h b/include/mincrypt/hash-internal.h
new file mode 100644
index 0000000..96806f7
--- /dev/null
+++ b/include/mincrypt/hash-internal.h
@@ -0,0 +1,40 @@
+// Copyright 2007 Google Inc. All Rights Reserved.
+// Author: mschilder@google.com (Marius Schilder)
+
+#ifndef SECURITY_UTIL_LITE_HASH_INTERNAL_H__
+#define SECURITY_UTIL_LITE_HASH_INTERNAL_H__
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+struct HASH_CTX; // forward decl
+
+typedef struct HASH_VTAB {
+ void (* const init)(struct HASH_CTX*);
+ void (* const update)(struct HASH_CTX*, const void*, int);
+ const uint8_t* (* const final)(struct HASH_CTX*);
+ const uint8_t* (* const hash)(const void*, int, uint8_t*);
+ int size;
+} HASH_VTAB;
+
+typedef struct HASH_CTX {
+ const HASH_VTAB * f;
+ uint64_t count;
+ uint8_t buf[64];
+ uint32_t state[8]; // upto SHA2
+} HASH_CTX;
+
+#define HASH_init(ctx) (ctx)->f->init(ctx)
+#define HASH_update(ctx, data, len) (ctx)->f->update(ctx, data, len)
+#define HASH_final(ctx) (ctx)->f->final(ctx)
+#define HASH_hash(data, len, digest) (ctx)->f->hash(data, len, digest)
+#define HASH_size(ctx) (ctx)->f->size
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // SECURITY_UTIL_LITE_HASH_INTERNAL_H__
diff --git a/include/mincrypt/rsa.h b/include/mincrypt/rsa.h
index d7429fc..cc0e800 100644
--- a/include/mincrypt/rsa.h
+++ b/include/mincrypt/rsa.h
@@ -48,7 +48,8 @@ typedef struct RSAPublicKey {
int RSA_verify(const RSAPublicKey *key,
const uint8_t* signature,
const int len,
- const uint8_t* sha);
+ const uint8_t* hash,
+ const int hash_len);
#ifdef __cplusplus
}
diff --git a/include/mincrypt/sha.h b/include/mincrypt/sha.h
index af63e87..120ddcb 100644
--- a/include/mincrypt/sha.h
+++ b/include/mincrypt/sha.h
@@ -1,63 +1,30 @@
-/* sha.h
-**
-** 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.
-*/
-
-#ifndef _EMBEDDED_SHA_H_
-#define _EMBEDDED_SHA_H_
-
-#include <inttypes.h>
+// Copyright 2005 Google Inc. All Rights Reserved.
+// Author: mschilder@google.com (Marius Schilder)
+
+#ifndef SECURITY_UTIL_LITE_SHA1_H__
+#define SECURITY_UTIL_LITE_SHA1_H__
+
+#include <stdint.h>
+#include "hash-internal.h"
#ifdef __cplusplus
extern "C" {
-#endif
-
-typedef struct SHA_CTX {
- uint64_t count;
- uint32_t state[5];
-#if defined(HAVE_ENDIAN_H) && defined(HAVE_LITTLE_ENDIAN)
- union {
- uint8_t b[64];
- uint32_t w[16];
- } buf;
-#else
- uint8_t buf[64];
-#endif
-} SHA_CTX;
+#endif // __cplusplus
+
+typedef HASH_CTX SHA_CTX;
void SHA_init(SHA_CTX* ctx);
void SHA_update(SHA_CTX* ctx, const void* data, int len);
const uint8_t* SHA_final(SHA_CTX* ctx);
-/* Convenience method. Returns digest parameter value. */
-const uint8_t* SHA(const void* data, int len, uint8_t* digest);
+// Convenience method. Returns digest address.
+// NOTE: *digest needs to hold SHA_DIGEST_SIZE bytes.
+const uint8_t* SHA_hash(const void* data, int len, uint8_t* digest);
#define SHA_DIGEST_SIZE 20
#ifdef __cplusplus
}
-#endif
+#endif // __cplusplus
-#endif
+#endif // SECURITY_UTIL_LITE_SHA1_H__
diff --git a/include/mincrypt/sha256.h b/include/mincrypt/sha256.h
new file mode 100644
index 0000000..0f3efb7
--- /dev/null
+++ b/include/mincrypt/sha256.h
@@ -0,0 +1,29 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+// Author: mschilder@google.com (Marius Schilder)
+
+#ifndef SECURITY_UTIL_LITE_SHA256_H__
+#define SECURITY_UTIL_LITE_SHA256_H__
+
+#include <stdint.h>
+#include "hash-internal.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+typedef HASH_CTX SHA256_CTX;
+
+void SHA256_init(SHA256_CTX* ctx);
+void SHA256_update(SHA256_CTX* ctx, const void* data, int len);
+const uint8_t* SHA256_final(SHA256_CTX* ctx);
+
+// Convenience method. Returns digest address.
+const uint8_t* SHA256_hash(const void* data, int len, uint8_t* digest);
+
+#define SHA256_DIGEST_SIZE 32
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // SECURITY_UTIL_LITE_SHA256_H__
diff --git a/libmincrypt/Android.mk b/libmincrypt/Android.mk
index f58eab9..addbed8 100644
--- a/libmincrypt/Android.mk
+++ b/libmincrypt/Android.mk
@@ -4,13 +4,13 @@ LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libmincrypt
-LOCAL_SRC_FILES := rsa.c rsa_e_3.c rsa_e_f4.c sha.c
+LOCAL_SRC_FILES := rsa.c rsa_e_3.c rsa_e_f4.c sha.c sha256.c
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := libmincrypt
-LOCAL_SRC_FILES := rsa.c rsa_e_3.c rsa_e_f4.c sha.c
+LOCAL_SRC_FILES := rsa.c rsa_e_3.c rsa_e_f4.c sha.c sha256.c
include $(BUILD_HOST_STATIC_LIBRARY)
diff --git a/libmincrypt/rsa.c b/libmincrypt/rsa.c
index b4ee6af..0cdbaa2 100644
--- a/libmincrypt/rsa.c
+++ b/libmincrypt/rsa.c
@@ -30,23 +30,26 @@
int RSA_e_f4_verify(const RSAPublicKey* key,
const uint8_t* signature,
const int len,
- const uint8_t* sha);
+ const uint8_t* hash,
+ const int hash_len);
int RSA_e_3_verify(const RSAPublicKey *key,
const uint8_t *signature,
const int len,
- const uint8_t *sha);
+ const uint8_t *hash,
+ const int hash_len);
int RSA_verify(const RSAPublicKey *key,
const uint8_t *signature,
const int len,
- const uint8_t *sha) {
+ const uint8_t *hash,
+ const int hash_len) {
switch (key->exponent) {
case 3:
- return RSA_e_3_verify(key, signature, len, sha);
+ return RSA_e_3_verify(key, signature, len, hash, hash_len);
break;
case 65537:
- return RSA_e_f4_verify(key, signature, len, sha);
+ return RSA_e_f4_verify(key, signature, len, hash, hash_len);
break;
default:
return 0;
diff --git a/libmincrypt/rsa_e_3.c b/libmincrypt/rsa_e_3.c
index c8c02c4..012a357 100644
--- a/libmincrypt/rsa_e_3.c
+++ b/libmincrypt/rsa_e_3.c
@@ -27,6 +27,7 @@
#include "mincrypt/rsa.h"
#include "mincrypt/sha.h"
+#include "mincrypt/sha256.h"
/* a[] -= mod */
static void subM(const RSAPublicKey *key, uint32_t *a) {
@@ -134,7 +135,7 @@ static void modpow3(const RSAPublicKey *key,
** 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] = {
+static const uint8_t sha_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,
@@ -156,15 +157,56 @@ static const uint8_t padding[RSANUMBYTES - SHA_DIGEST_SIZE] = {
0x04,0x14
};
+static const uint8_t sha256_padding[RSANUMBYTES - SHA256_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,0x00,0x30,0x31,0x30,
+ 0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,
+ 0x00,0x04,0x20
+};
+
+
/* Verify a 2048 bit RSA e=3 PKCS1.5 signature against an expected SHA-1 hash.
** Returns 0 on failure, 1 on success.
*/
int RSA_e_3_verify(const RSAPublicKey *key,
const uint8_t *signature,
const int len,
- const uint8_t *sha) {
+ const uint8_t *hash,
+ const int hash_len) {
uint8_t buf[RSANUMBYTES];
int i;
+ int padding_size;
+ const uint8_t* padding;
+
+ switch (hash_len) {
+ case SHA_DIGEST_SIZE:
+ padding = sha_padding;
+ padding_size = sizeof(sha_padding);
+ break;
+ case SHA256_DIGEST_SIZE:
+ padding = sha256_padding;
+ padding_size = sizeof(sha256_padding);
+ break;
+ default:
+ return 0; // unsupported hash
+ }
if (key->len != RSANUMWORDS) {
return 0; /* Wrong key passed in. */
@@ -185,7 +227,7 @@ int RSA_e_3_verify(const RSAPublicKey *key,
modpow3(key, buf);
/* Check pkcs1.5 padding bytes. */
- for (i = 0; i < (int) sizeof(padding); ++i) {
+ for (i = 0; i < padding_size; ++i) {
if (buf[i] != padding[i]) {
return 0;
}
@@ -193,7 +235,7 @@ int RSA_e_3_verify(const RSAPublicKey *key,
/* Check sha digest matches. */
for (; i < len; ++i) {
- if (buf[i] != *sha++) {
+ if (buf[i] != *hash++) {
return 0;
}
}
diff --git a/libmincrypt/rsa_e_f4.c b/libmincrypt/rsa_e_f4.c
index 6701bcc..17a2de2 100644
--- a/libmincrypt/rsa_e_f4.c
+++ b/libmincrypt/rsa_e_f4.c
@@ -27,6 +27,7 @@
#include "mincrypt/rsa.h"
#include "mincrypt/sha.h"
+#include "mincrypt/sha256.h"
// a[] -= mod
static void subM(const RSAPublicKey* key,
@@ -138,26 +139,79 @@ static void modpowF4(const RSAPublicKey* key,
// other flavor which omits the optional parameter entirely). This code does not
// accept signatures without the optional parameter.
/*
-static const uint8_t padding[RSANUMBYTES] = {
+static const uint8_t sha_padding[RSANUMBYTES] = {
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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};
+
+static const uint8_t sha256_padding[RSANUMBYTES] = {
+ 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,0x00,0x30,0x31,0x30,
+ 0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,
+ 0x00,0x04,0x20,
+
+ // 32 bytes of hash go here.
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+};
+
*/
-// SHA-1 of PKCS1.5 signature padding for 2048 bit, as above.
+// SHA-1 of PKCS1.5 signature sha_padding for 2048 bit, as above.
// At the location of the bytes of the hash all 00 are hashed.
static const uint8_t kExpectedPadShaRsa2048[SHA_DIGEST_SIZE] = {
0xdc, 0xbd, 0xbe, 0x42, 0xd5, 0xf5, 0xa7, 0x2e, 0x6e, 0xfc,
0xf5, 0x5d, 0xaf, 0x9d, 0xea, 0x68, 0x7c, 0xfb, 0xf1, 0x67
};
+// SHA-256 of PKCS1.5 signature sha256_padding for 2048 bit, as above.
+// At the location of the bytes of the hash all 00 are hashed.
+static const uint8_t kExpectedPadSha256Rsa2048[SHA256_DIGEST_SIZE] = {
+ 0xab, 0x28, 0x8d, 0x8a, 0xd7, 0xd9, 0x59, 0x92,
+ 0xba, 0xcc, 0xf8, 0x67, 0x20, 0xe1, 0x15, 0x2e,
+ 0x39, 0x8d, 0x80, 0x36, 0xd6, 0x6f, 0xf0, 0xfd,
+ 0x90, 0xe8, 0x7d, 0x8b, 0xe1, 0x7c, 0x87, 0x59,
+};
+
// Verify a 2048 bit RSA e=65537 PKCS1.5 signature against an expected
// SHA-1 hash. Returns 0 on failure, 1 on success.
int RSA_e_f4_verify(const RSAPublicKey* key,
const uint8_t* signature,
const int len,
- const uint8_t* sha) {
+ const uint8_t* hash,
+ const int hash_len) {
uint8_t buf[RSANUMBYTES];
int i;
+ const uint8_t* padding_hash;
+
+ switch (hash_len) {
+ case SHA_DIGEST_SIZE:
+ padding_hash = kExpectedPadShaRsa2048;
+ break;
+ case SHA256_DIGEST_SIZE:
+ padding_hash = kExpectedPadSha256Rsa2048;
+ break;
+ default:
+ return 0; // unsupported hash
+ }
if (key->len != RSANUMWORDS) {
return 0; // Wrong key passed in.
@@ -178,16 +232,25 @@ int RSA_e_f4_verify(const RSAPublicKey* key,
modpowF4(key, buf); // In-place exponentiation.
// Xor sha portion, so it all becomes 00 iff equal.
- for (i = len - SHA_DIGEST_SIZE; i < len; ++i) {
- buf[i] ^= *sha++;
+ for (i = len - hash_len; i < len; ++i) {
+ buf[i] ^= *hash++;
}
// Hash resulting buf, in-place.
- SHA(buf, len, buf);
+ switch (hash_len) {
+ case SHA_DIGEST_SIZE:
+ SHA_hash(buf, len, buf);
+ break;
+ case SHA256_DIGEST_SIZE:
+ SHA256_hash(buf, len, buf);
+ break;
+ default:
+ return 0;
+ }
// Compare against expected hash value.
- for (i = 0; i < SHA_DIGEST_SIZE; ++i) {
- if (buf[i] != kExpectedPadShaRsa2048[i]) {
+ for (i = 0; i < hash_len; ++i) {
+ if (buf[i] != padding_hash[i]) {
return 0;
}
}
diff --git a/libmincrypt/sha.c b/libmincrypt/sha.c
index e089d79..5bef32e 100644
--- a/libmincrypt/sha.c
+++ b/libmincrypt/sha.c
@@ -1,6 +1,6 @@
/* sha.c
**
-** Copyright 2008, The Android Open Source Project
+** Copyright 2013, 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:
@@ -25,177 +25,20 @@
** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "mincrypt/sha.h"
-
-// Some machines lack byteswap.h and endian.h. These have to use the
-// slower code, even if they're little-endian.
-
-#if defined(HAVE_ENDIAN_H) && defined(HAVE_LITTLE_ENDIAN)
-
-#include <byteswap.h>
-#include <memory.h>
-
-// This version is about 28% faster than the generic version below,
-// but assumes little-endianness.
-
-static inline uint32_t ror27(uint32_t val) {
- return (val >> 27) | (val << 5);
-}
-static inline uint32_t ror2(uint32_t val) {
- return (val >> 2) | (val << 30);
-}
-static inline uint32_t ror31(uint32_t val) {
- return (val >> 31) | (val << 1);
-}
-
-static void SHA1_Transform(SHA_CTX* ctx) {
- uint32_t W[80];
- register uint32_t A, B, C, D, E;
- int t;
-
- A = ctx->state[0];
- B = ctx->state[1];
- C = ctx->state[2];
- D = ctx->state[3];
- E = ctx->state[4];
-
-#define SHA_F1(A,B,C,D,E,t) \
- E += ror27(A) + \
- (W[t] = bswap_32(ctx->buf.w[t])) + \
- (D^(B&(C^D))) + 0x5A827999; \
- B = ror2(B);
-
- for (t = 0; t < 15; t += 5) {
- SHA_F1(A,B,C,D,E,t + 0);
- SHA_F1(E,A,B,C,D,t + 1);
- SHA_F1(D,E,A,B,C,t + 2);
- SHA_F1(C,D,E,A,B,t + 3);
- SHA_F1(B,C,D,E,A,t + 4);
- }
- SHA_F1(A,B,C,D,E,t + 0); // 16th one, t == 15
-
-#undef SHA_F1
-
-#define SHA_F1(A,B,C,D,E,t) \
- E += ror27(A) + \
- (W[t] = ror31(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16])) + \
- (D^(B&(C^D))) + 0x5A827999; \
- B = ror2(B);
-
- SHA_F1(E,A,B,C,D,t + 1);
- SHA_F1(D,E,A,B,C,t + 2);
- SHA_F1(C,D,E,A,B,t + 3);
- SHA_F1(B,C,D,E,A,t + 4);
-
-#undef SHA_F1
-
-#define SHA_F2(A,B,C,D,E,t) \
- E += ror27(A) + \
- (W[t] = ror31(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16])) + \
- (B^C^D) + 0x6ED9EBA1; \
- B = ror2(B);
-
- for (t = 20; t < 40; t += 5) {
- SHA_F2(A,B,C,D,E,t + 0);
- SHA_F2(E,A,B,C,D,t + 1);
- SHA_F2(D,E,A,B,C,t + 2);
- SHA_F2(C,D,E,A,B,t + 3);
- SHA_F2(B,C,D,E,A,t + 4);
- }
-
-#undef SHA_F2
-
-#define SHA_F3(A,B,C,D,E,t) \
- E += ror27(A) + \
- (W[t] = ror31(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16])) + \
- ((B&C)|(D&(B|C))) + 0x8F1BBCDC; \
- B = ror2(B);
-
- for (; t < 60; t += 5) {
- SHA_F3(A,B,C,D,E,t + 0);
- SHA_F3(E,A,B,C,D,t + 1);
- SHA_F3(D,E,A,B,C,t + 2);
- SHA_F3(C,D,E,A,B,t + 3);
- SHA_F3(B,C,D,E,A,t + 4);
- }
-
-#undef SHA_F3
-
-#define SHA_F4(A,B,C,D,E,t) \
- E += ror27(A) + \
- (W[t] = ror31(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16])) + \
- (B^C^D) + 0xCA62C1D6; \
- B = ror2(B);
-
- for (; t < 80; t += 5) {
- SHA_F4(A,B,C,D,E,t + 0);
- SHA_F4(E,A,B,C,D,t + 1);
- SHA_F4(D,E,A,B,C,t + 2);
- SHA_F4(C,D,E,A,B,t + 3);
- SHA_F4(B,C,D,E,A,t + 4);
- }
-
-#undef SHA_F4
-
- ctx->state[0] += A;
- ctx->state[1] += B;
- ctx->state[2] += C;
- ctx->state[3] += D;
- ctx->state[4] += E;
-}
-
-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 > sizeof(ctx->buf) - i) {
- memcpy(&ctx->buf.b[i], p, sizeof(ctx->buf) - i);
- len -= sizeof(ctx->buf) - i;
- p += sizeof(ctx->buf) - i;
- SHA1_Transform(ctx);
- i = 0;
- }
-
- while (len--) {
- ctx->buf.b[i++] = *p++;
- if (i == sizeof(ctx->buf)) {
- SHA1_Transform(ctx);
- i = 0;
- }
- }
-}
-
+// Optimized for minimal code size.
-const uint8_t* SHA_final(SHA_CTX* ctx) {
- 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++) {
- ctx->buf.w[i] = bswap_32(ctx->state[i]);
- }
-
- return ctx->buf.b;
-}
+#include "mincrypt/sha.h"
-#else // #if defined(HAVE_ENDIAN_H) && defined(HAVE_LITTLE_ENDIAN)
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
#define rol(bits, value) (((value) << (bits)) | ((value) >> (32 - (bits))))
-static void SHA1_transform(SHA_CTX *ctx) {
+static void SHA1_Transform(SHA_CTX* ctx) {
uint32_t W[80];
uint32_t A, B, C, D, E;
- uint8_t *p = ctx->buf;
+ uint8_t* p = ctx->buf;
int t;
for(t = 0; t < 16; ++t) {
@@ -242,31 +85,52 @@ static void SHA1_transform(SHA_CTX *ctx) {
ctx->state[4] += E;
}
-void SHA_update(SHA_CTX *ctx, const void *data, int len) {
- int i = ctx->count % sizeof(ctx->buf);
+static const HASH_VTAB SHA_VTAB = {
+ SHA_init,
+ SHA_update,
+ SHA_final,
+ SHA_hash,
+ SHA_DIGEST_SIZE
+};
+
+void SHA_init(SHA_CTX* ctx) {
+ ctx->f = &SHA_VTAB;
+ 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 = (int) (ctx->count & 63);
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);
+ if (i == 64) {
+ SHA1_Transform(ctx);
i = 0;
}
}
}
-const uint8_t *SHA_final(SHA_CTX *ctx) {
+
+
+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)) {
+ while ((ctx->count & 63) != 56) {
SHA_update(ctx, (uint8_t*)"\0", 1);
}
for (i = 0; i < 8; ++i) {
- uint8_t tmp = cnt >> ((7 - i) * 8);
+ uint8_t tmp = (uint8_t) (cnt >> ((7 - i) * 8));
SHA_update(ctx, &tmp, 1);
}
@@ -281,27 +145,11 @@ const uint8_t *SHA_final(SHA_CTX *ctx) {
return ctx->buf;
}
-#endif // endianness
-
-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;
-}
-
/* Convenience function */
-const uint8_t* SHA(const void *data, int len, uint8_t *digest) {
- const uint8_t *p;
- int i;
+const uint8_t* SHA_hash(const void* data, int len, uint8_t* digest) {
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++;
- }
+ memcpy(digest, SHA_final(&ctx), SHA_DIGEST_SIZE);
return digest;
}
diff --git a/libmincrypt/sha256.c b/libmincrypt/sha256.c
new file mode 100644
index 0000000..eb6e308
--- /dev/null
+++ b/libmincrypt/sha256.c
@@ -0,0 +1,184 @@
+/* sha256.c
+**
+** Copyright 2013, 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.
+*/
+
+// Optimized for minimal code size.
+
+#include "mincrypt/sha256.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+#define ror(value, bits) (((value) >> (bits)) | ((value) << (32 - (bits))))
+#define shr(value, bits) ((value) >> (bits))
+
+static const uint32_t K[64] = {
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
+ 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+ 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
+ 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
+ 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+ 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
+ 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
+ 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+ 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 };
+
+static void SHA256_Transform(SHA256_CTX* ctx) {
+ uint32_t W[64];
+ uint32_t A, B, C, D, E, F, G, H;
+ 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 < 64; t++) {
+ uint32_t s0 = ror(W[t-15], 7) ^ ror(W[t-15], 18) ^ shr(W[t-15], 3);
+ uint32_t s1 = ror(W[t-2], 17) ^ ror(W[t-2], 19) ^ shr(W[t-2], 10);
+ W[t] = W[t-16] + s0 + W[t-7] + s1;
+ }
+
+ A = ctx->state[0];
+ B = ctx->state[1];
+ C = ctx->state[2];
+ D = ctx->state[3];
+ E = ctx->state[4];
+ F = ctx->state[5];
+ G = ctx->state[6];
+ H = ctx->state[7];
+
+ for(t = 0; t < 64; t++) {
+ uint32_t s0 = ror(A, 2) ^ ror(A, 13) ^ ror(A, 22);
+ uint32_t maj = (A & B) ^ (A & C) ^ (B & C);
+ uint32_t t2 = s0 + maj;
+ uint32_t s1 = ror(E, 6) ^ ror(E, 11) ^ ror(E, 25);
+ uint32_t ch = (E & F) ^ ((~E) & G);
+ uint32_t t1 = H + s1 + ch + K[t] + W[t];
+
+ H = G;
+ G = F;
+ F = E;
+ E = D + t1;
+ D = C;
+ C = B;
+ B = A;
+ A = t1 + t2;
+ }
+
+ ctx->state[0] += A;
+ ctx->state[1] += B;
+ ctx->state[2] += C;
+ ctx->state[3] += D;
+ ctx->state[4] += E;
+ ctx->state[5] += F;
+ ctx->state[6] += G;
+ ctx->state[7] += H;
+}
+
+static const HASH_VTAB SHA256_VTAB = {
+ SHA256_init,
+ SHA256_update,
+ SHA256_final,
+ SHA256_hash,
+ SHA256_DIGEST_SIZE
+};
+
+void SHA256_init(SHA256_CTX* ctx) {
+ ctx->f = &SHA256_VTAB;
+ ctx->state[0] = 0x6a09e667;
+ ctx->state[1] = 0xbb67ae85;
+ ctx->state[2] = 0x3c6ef372;
+ ctx->state[3] = 0xa54ff53a;
+ ctx->state[4] = 0x510e527f;
+ ctx->state[5] = 0x9b05688c;
+ ctx->state[6] = 0x1f83d9ab;
+ ctx->state[7] = 0x5be0cd19;
+ ctx->count = 0;
+}
+
+
+void SHA256_update(SHA256_CTX* ctx, const void* data, int len) {
+ int i = (int) (ctx->count & 63);
+ const uint8_t* p = (const uint8_t*)data;
+
+ ctx->count += len;
+
+ while (len--) {
+ ctx->buf[i++] = *p++;
+ if (i == 64) {
+ SHA256_Transform(ctx);
+ i = 0;
+ }
+ }
+}
+
+
+const uint8_t* SHA256_final(SHA256_CTX* ctx) {
+ uint8_t *p = ctx->buf;
+ uint64_t cnt = ctx->count * 8;
+ int i;
+
+ SHA256_update(ctx, (uint8_t*)"\x80", 1);
+ while ((ctx->count & 63) != 56) {
+ SHA256_update(ctx, (uint8_t*)"\0", 1);
+ }
+ for (i = 0; i < 8; ++i) {
+ uint8_t tmp = (uint8_t) (cnt >> ((7 - i) * 8));
+ SHA256_update(ctx, &tmp, 1);
+ }
+
+ for (i = 0; i < 8; 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* SHA256_hash(const void* data, int len, uint8_t* digest) {
+ SHA256_CTX ctx;
+ SHA256_init(&ctx);
+ SHA256_update(&ctx, data, len);
+ memcpy(digest, SHA256_final(&ctx), SHA256_DIGEST_SIZE);
+ return digest;
+}
diff --git a/libmincrypt/tools/DumpPublicKey.java b/libmincrypt/tools/DumpPublicKey.java
index 12b4f56..7189116 100644
--- a/libmincrypt/tools/DumpPublicKey.java
+++ b/libmincrypt/tools/DumpPublicKey.java
@@ -19,7 +19,7 @@ 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.cert.X509Certificate;
import java.security.KeyStore;
import java.security.Key;
import java.security.PublicKey;
@@ -34,20 +34,22 @@ class DumpPublicKey {
/**
* @param key to perform sanity checks on
* @return version number of key. Supported versions are:
- * 1: 2048-bit key with e=3
- * 2: 2048-bit key with e=65537
+ * 1: 2048-bit RSA key with e=3 and SHA-1 hash
+ * 2: 2048-bit RSA key with e=65537 and SHA-1 hash
+ * 3: 2048-bit RSA key with e=3 and SHA-256 hash
+ * 4: 2048-bit RSA key with e=65537 and SHA-256 hash
* @throws Exception if the key has the wrong size or public exponent
*/
- static int check(RSAPublicKey key) throws Exception {
+ static int check(RSAPublicKey key, boolean useSHA256) throws Exception {
BigInteger pubexp = key.getPublicExponent();
BigInteger modulus = key.getModulus();
int version;
if (pubexp.equals(BigInteger.valueOf(3))) {
- version = 1;
+ version = useSHA256 ? 3 : 1;
} else if (pubexp.equals(BigInteger.valueOf(65537))) {
- version = 2;
+ version = useSHA256 ? 4 : 2;
} else {
throw new Exception("Public exponent should be 3 or 65537 but is " +
pubexp.toString(10) + ".");
@@ -67,8 +69,8 @@ class DumpPublicKey {
* version 1 key, the string will be a C initializer; this is
* not true for newer key versions.
*/
- static String print(RSAPublicKey key) throws Exception {
- int version = check(key);
+ static String print(RSAPublicKey key, boolean useSHA256) throws Exception {
+ int version = check(key, useSHA256);
BigInteger N = key.getModulus();
@@ -135,10 +137,27 @@ class DumpPublicKey {
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);
+ X509Certificate cert = (X509Certificate) cf.generateCertificate(input);
+
+ boolean useSHA256 = false;
+ String sigAlg = cert.getSigAlgName();
+ if ("SHA1withRSA".equals(sigAlg) || "MD5withRSA".equals(sigAlg)) {
+ // SignApk has historically accepted "MD5withRSA"
+ // certificates, but treated them as "SHA1withRSA"
+ // anyway. Continue to do so for backwards
+ // compatibility.
+ useSHA256 = false;
+ } else if ("SHA256withRSA".equals(sigAlg)) {
+ useSHA256 = true;
+ } else {
+ System.err.println(args[i] + ": unsupported signature algorithm \"" +
+ sigAlg + "\"");
+ System.exit(1);
+ }
+
RSAPublicKey key = (RSAPublicKey) (cert.getPublicKey());
- check(key);
- System.out.print(print(key));
+ check(key, useSHA256);
+ System.out.print(print(key, useSHA256));
System.out.println(i < args.length - 1 ? "," : "");
}
} catch (Exception e) {