diff options
author | Doug Zongker <dougz@android.com> | 2013-04-10 09:22:02 -0700 |
---|---|---|
committer | Kenny Root <kroot@google.com> | 2013-09-25 09:26:34 -0700 |
commit | 8e5b63d045e988f13d1ee9b7797db28fde15bbfc (patch) | |
tree | aaac24d144489aeeca8dcd002579e882445233a6 | |
parent | 3c8bdef029cbaa8d8fa18e4e55e51b60e938dd6e (diff) | |
download | system_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.c | 3 | ||||
-rw-r--r-- | include/mincrypt/hash-internal.h | 40 | ||||
-rw-r--r-- | include/mincrypt/rsa.h | 3 | ||||
-rw-r--r-- | include/mincrypt/sha.h | 65 | ||||
-rw-r--r-- | include/mincrypt/sha256.h | 29 | ||||
-rw-r--r-- | libmincrypt/Android.mk | 4 | ||||
-rw-r--r-- | libmincrypt/rsa.c | 13 | ||||
-rw-r--r-- | libmincrypt/rsa_e_3.c | 50 | ||||
-rw-r--r-- | libmincrypt/rsa_e_f4.c | 79 | ||||
-rw-r--r-- | libmincrypt/sha.c | 228 | ||||
-rw-r--r-- | libmincrypt/sha256.c | 184 | ||||
-rw-r--r-- | libmincrypt/tools/DumpPublicKey.java | 41 |
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) { |