Index: base/security/rsa.cc |
diff --git a/base/security/rsa.cc b/base/security/rsa.cc |
deleted file mode 100644 |
index 4f3d1040f73539b1fa215fca0c34cca3cfeaa51b..0000000000000000000000000000000000000000 |
--- a/base/security/rsa.cc |
+++ /dev/null |
@@ -1,290 +0,0 @@ |
-// Copyright 2006-2009 Google Inc. |
-// |
-// 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. |
-// ======================================================================== |
- |
-#include "rsa.h" |
- |
-#include <stddef.h> |
-#include <inttypes.h> |
-#include <string.h> |
-#include <stdio.h> |
- |
-#include "md5.h" |
-#include "aes.h" |
-#include "sha.h" |
-#include "rc4.h" |
- |
-#define DINV mod[0] |
-#define RR(i) mod[1 + 2*(i)] |
-#define MOD(i) (mod[2 + 2*(i)] + mod[1 + 2*(i)]) // +mod[1+2*(i)] to deobscure |
- |
-// |
-// a[] -= M |
-// |
-static void subM(uint32_t* a, const uint32_t* mod, int len) { |
- int64_t A = 0; |
- for (int i = 0; i < len; ++i) { |
- A += (uint64_t)a[i] - MOD(i); |
- a[i] = (uint32_t)A; |
- A >>= 32; |
- } |
-} |
- |
-// |
-// return a[] >= M |
-// |
-static bool geM(const uint32_t* a, const uint32_t* mod, int len) { |
- for (int i = len; i;) { |
- --i; |
- if (a[i] < MOD(i)) return false; |
- if (a[i] > MOD(i)) return true; |
- } |
- return true; // equal |
-} |
- |
-// |
-// montgomery c[] += a * b[] / R mod M |
-// |
-static void montMulAdd(uint32_t* c, |
- uint32_t a, |
- const uint32_t* b, |
- const uint32_t* mod, |
- int len) { |
- uint64_t A = (uint64_t)a * b[0] + c[0]; |
- uint32_t d0 = (uint32_t)A * DINV; |
- uint64_t B = (uint64_t)d0 * MOD(0) + (uint32_t)A; |
- |
- int i = 1; |
- for (; i < len; ++i) { |
- A = (A >> 32) + (uint64_t)a * b[i] + c[i]; |
- B = (B >> 32) + (uint64_t)d0 * MOD(i) + (uint32_t)A; |
- c[i - 1] = (uint32_t)B; |
- } |
- |
- A = (A >> 32) + (B >> 32); |
- |
- c[i - 1] = (uint32_t)A; |
- |
- if ((A >> 32)) { // proper probablistic padding could avoid this? |
- subM(c, mod, len); // or moduli without the highest bit set.. |
- } |
-} |
- |
-// |
-// montgomery c[] = a[] * R^2 / R mod M (= a[] * R mod M) |
-// |
-static void montMulR(uint32_t* c, |
- const uint32_t* a, |
- const uint32_t* mod, |
- int len) { |
- memset(c, 0, len * sizeof(uint32_t)); |
- |
- for (int i = 0; i < len; ++i) { |
- montMulAdd(c, RR(i), a, mod, len); |
- } |
-} |
- |
-// |
-// montgomery c[] = a[] * b[] / R mod M |
-// |
-static void montMul(uint32_t* c, |
- const uint32_t* a, |
- const uint32_t* b, |
- const uint32_t* mod, |
- int len) { |
- memset(c, 0, len * sizeof(uint32_t)); |
- |
- for (int i = 0; i < len; ++i) { |
- montMulAdd(c, a[i], b, mod, len); |
- } |
-} |
- |
- |
-// |
-// In-place public exponentiation. |
-// Input and output big-endian byte array. |
-// Returns 0 on failure or # uint8_t written in inout (always inout_len). |
-// |
-int RSA::raw(uint8_t* inout, int inout_len) const { |
- const uint32_t* mod = &pkey_[1]; |
- int len = *mod++; |
- |
- if (len > kMaxWords) |
- return 0; // Only work with up to 2048 bit moduli. |
- if ((len * 4) != inout_len) |
- return 0; // Input length should match modulus length. |
- |
- uint32_t a[kMaxWords]; |
- |
- // Convert from big endian byte array to little endian word array. |
- for (int i = 0; i < len; ++i) { |
- uint32_t tmp = |
- (inout[((len - 1 - i) * 4) + 0] << 24) | |
- (inout[((len - 1 - i) * 4) + 1] << 16) | |
- (inout[((len - 1 - i) * 4) + 2] << 8) | |
- (inout[((len - 1 - i) * 4) + 3] << 0); |
- a[i] = tmp; |
- } |
- |
- uint32_t aR[kMaxWords]; |
- uint32_t aaR[kMaxWords]; |
- uint32_t aaa[kMaxWords]; |
- |
- montMulR(aR, a, mod, len); // aR = a * R mod M |
- montMul(aaR, aR, aR, mod, len); // aaR = a^2 * R mod M |
- montMul(aaa, aaR, a, mod, len); // aaa = a^3 mod M |
- |
- // Make sure aaa < mod; aaa is at most 1x mod too large. |
- if (geM(aaa, mod, len)) { |
- subM(aaa, mod, len); |
- } |
- |
- // Convert to bigendian byte array |
- int reslen = 0; |
- |
- for (int i = len - 1; i >= 0; --i) { |
- uint32_t tmp = aaa[i]; |
- inout[reslen++] = tmp >> 24; |
- inout[reslen++] = tmp >> 16; |
- inout[reslen++] = tmp >> 8; |
- inout[reslen++] = tmp >> 0; |
- } |
- |
- return reslen; |
-} |
- |
-// |
-// Verify a Google style padded message recovery signature and return the |
-// message. |
-// |
-int RSA::verify(const uint8_t* data, int data_len, |
- void* output, int output_len) const { |
- uint8_t res[kMaxWords * 4]; |
- |
- if (data_len < 0 || data_len > (kMaxWords * 4)) |
- return 0; // Input too big, 2048 bit max. |
- |
- memcpy(res, data, data_len); |
- |
- int reslen = this->raw(res, data_len); |
- |
- if (!reslen) return 0; |
- |
- uint8_t md5[16]; |
- |
- MD5(res, reslen - 16, md5); |
- |
- for (int i = 0; i < 16; ++i) { |
- res[reslen - 16 + i] ^= md5[i]; |
- } |
- |
- // Unmask low part using high part as ofb key. |
- uint8_t iv[16] = {0}; |
- |
- for (int i = 0; i < reslen - 16; i++) { |
- if (!(i & 15)) |
- AES_encrypt_block(res + reslen - 16, iv, iv); |
- res[i] ^= iv[i & 15]; |
- } |
- |
- res[0] &= 127; |
- res[0] %= reslen - 16 - 16; |
- |
- bool result = true; |
- |
- // Verify high part is hash of random in low part. |
- MD5(res + 1, res[0] + 16, md5); |
- for (int i = 0; i < 16; ++i) { |
- result = result && (res[reslen - 16 + i] == md5[i]); |
- } |
- |
- if (!result) { |
- return 0; // verification failure |
- } |
- |
- // Copy message into output[] |
- if (res[0] > output_len) { |
- return 0; // output too small, return failure |
- } |
- |
- memcpy(output, res + 1, res[0]); |
- |
- return res[0]; |
-} |
- |
-// |
-// Hybrid encrypt message. |
-// Make up RC4 key using seed and hash of msg. |
-// Wrap key with RSA, encrypt msg with RC4. |
-// |
-int RSA::encrypt(const uint8_t* msg, int msg_len, |
- const void* seed, int seed_len, |
- uint8_t* output, int output_max) const { |
- int output_len = this->encryptedSize(msg_len); |
- if (output_max < 0 || output_max < output_len) |
- return 0; |
- |
- int header_size = output_len - msg_len; // Our added overhead. |
- |
- // Hash of message. Least significant SHA_DIGEST_SIZE bytes of RSA number. |
- uint8_t* hash = &output[header_size - SHA_DIGEST_SIZE]; |
- SHA(msg, msg_len, hash); |
- |
- // Hash(Hash(message) | seed). |
- SHA_CTX sha; |
- SHA_init(&sha); |
- SHA_update(&sha, hash, SHA_DIGEST_SIZE); |
- SHA_update(&sha, seed, seed_len); |
- |
- // Use this Hash(Hash(message) | seed) as RC4 key for prng. |
- RC4_CTX rc4; |
- RC4_setKey(&rc4, SHA_final(&sha), SHA_DIGEST_SIZE); |
- RC4_discard(&rc4, 1536); // Drop some to warm up RC4. |
- |
- uint8_t* key = &output[1 + 4]; |
- |
- // Prng conjure some bytes. |
- RC4_stream(&rc4, key, this->size() - SHA_DIGEST_SIZE); |
- key[0] &= 127; // Drop top bit to be less than modulus. |
- |
- // Mask plaintext hash with hash of prng part. |
- SHA_init(&sha); |
- SHA_update(&sha, key, this->size() - SHA_DIGEST_SIZE); |
- const uint8_t* mask = SHA_final(&sha); |
- for (int i = 0; i < SHA_DIGEST_SIZE; ++i) |
- hash[i] ^= mask[i]; |
- |
- // Use entire RSA number as content encryption key. |
- RC4_setKey(&rc4, key, this->size()); |
- RC4_discard(&rc4, 1536); // Warm up RC4. |
- |
- // Output wire-format version, single 0 byte. |
- output[0] = 0; |
- |
- // Output version, msb first. |
- uint32_t version = this->version(); |
- output[1] = version >> 24; |
- output[2] = version >> 16; |
- output[3] = version >> 8; |
- output[4] = version >> 0; |
- |
- // Wrap key data with public RSA key. |
- if (!this->raw(key, this->size())) |
- return 0; |
- |
- // Append encrypted message. |
- RC4_crypt(&rc4, msg, &output[header_size], msg_len); |
- |
- return output_len; |
-} |