普通文本  |  271行  |  6.95 KB

// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/devtools/adb/android_rsa.h"

#include "base/base64.h"
#include "base/memory/scoped_ptr.h"
#include "chrome/browser/prefs/pref_service_syncable.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "crypto/rsa_private_key.h"
#include "crypto/signature_creator.h"
#include "net/cert/asn1_util.h"

namespace {

const size_t kRSANumWords = 64;
const size_t kBigIntSize = 1024;

static const char kDummyRSAPublicKey[] =
    "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6OSJ64q+ZLg7VV2ojEPh5TRbYjwbT"
    "TifSPeFIV45CHnbTWYiiIn41wrozpYizNsMWZUBjdah1N78WVhbyDrnr0bDgFp+gXjfVppa3I"
    "gjiohEcemK3omXi3GDMK8ERhriLUKfQS842SXtQ8I+KoZtpCkGM//0h7+P+Rhm0WwdipIRMhR"
    "8haNAeyDiiCvqJcvevv2T52vqKtS3aWz+GjaTJJLVWydEpz9WdvWeLfFVhe2ZnqwwZNa30Qoj"
    "fsnvjaMwK2MU7uYfRBPuvLyK5QESWBpArNDd6ULl8Y+NU6kwNOVDc87OASCVEM1gw2IMi2mo2"
    "WO5ywp0UWRiGZCkK+wOFQIDAQAB";

typedef struct RSAPublicKey {
    int len;                // Length of n[] in number of uint32
    uint32 n0inv;           // -1 / n[0] mod 2^32
    uint32 n[kRSANumWords];  // modulus as little endian array
    uint32 rr[kRSANumWords]; // R^2 as little endian array
    int exponent;           // 3 or 65537
} RSAPublicKey;

// http://en.wikipedia.org/wiki/Extended_Euclidean_algorithm
// a * x + b * y = gcd(a, b) = d
void ExtendedEuclid(uint64 a, uint64 b, uint64 *x, uint64 *y, uint64 *d) {
  uint64 x1 = 0, x2 = 1, y1 = 1, y2 = 0;

  while (b > 0) {
    uint64 q = a / b;
    uint64 r = a % b;
    *x = x2 - q * x1;
    *y = y2 - q * y1;
    a = b;
    b = r;
    x2 = x1;
    x1 = *x;
    y2 = y1;
    y1 = *y;
  }

  *d = a;
  *x = x2;
  *y = y2;
}

uint32 ModInverse(uint64 a, uint64 m)
{
  uint64 d, x, y;
  ExtendedEuclid(a, m, &x, &y, &d);
  if (d == 1)
    return static_cast<uint32>(x);
  return 0;
}

uint32* BnNew() {
  uint32* result = new uint32[kBigIntSize];
  memset(result, 0, kBigIntSize * sizeof(uint32));
  return result;
}

void BnFree(uint32* a) {
  delete[] a;
}

uint32* BnCopy(uint32* a) {
  uint32* result = new uint32[kBigIntSize];
  memcpy(result, a, kBigIntSize * sizeof(uint32));
  return result;
}

uint32* BnMul(uint32* a, uint32 b) {
  uint32* result = BnNew();
  uint64 carry_over = 0;
  for (size_t i = 0; i < kBigIntSize; ++i) {
    carry_over += static_cast<uint64>(a[i]) * b;
    result[i] = carry_over & kuint32max;
    carry_over >>= 32;
  }
  return result;
}

void BnSub(uint32* a, uint32* b) {
  int carry_over = 0;
  for (size_t i = 0; i < kBigIntSize; ++i) {
    int64 sub = static_cast<int64>(a[i]) - b[i] - carry_over;
    carry_over = 0;
    if (sub < 0) {
      carry_over = 1;
      sub += GG_LONGLONG(0x100000000);
    }
    a[i] = static_cast<uint32>(sub);
  }
}

void BnLeftShift(uint32* a, int offset) {
  for (int i = kBigIntSize - offset - 1; i >= 0; --i)
    a[i + offset] = a[i];
  for (int i = 0; i < offset; ++i)
    a[i] = 0;
}

int BnCompare(uint32* a, uint32* b) {
  for (int i = kBigIntSize - 1; i >= 0; --i) {
    if (a[i] > b[i])
      return 1;
    if (a[i] < b[i])
      return -1;
  }
  return 0;
}

uint64 BnGuess(uint32* a, uint32* b, uint64 from, uint64 to) {
  if (from + 1 >= to)
    return from;

  uint64 guess = (from + to) / 2;
  uint32* t = BnMul(b, static_cast<uint32>(guess));
  int result = BnCompare(a, t);
  BnFree(t);
  if (result > 0)
    return BnGuess(a, b, guess, to);
  if (result < 0)
    return BnGuess(a, b, from, guess);
  return guess;
}

void BnDiv(uint32* a, uint32* b, uint32** pq, uint32** pr) {
  if (BnCompare(a, b) < 0) {
    if (pq)
      *pq = BnNew();
    if (pr)
      *pr = BnCopy(a);
    return;
  }

  int oa = kBigIntSize - 1;
  int ob = kBigIntSize - 1;
  for (; oa > 0 && !a[oa]; --oa) {}
  for (; ob > 0 && !b[ob]; --ob) {}
  uint32* q = BnNew();
  uint32* ca = BnCopy(a);

  int digit = a[oa] < b[ob] ? oa - ob - 1 : oa - ob;

  for (; digit >= 0; --digit) {
    uint32* shifted_b = BnCopy(b);
    BnLeftShift(shifted_b, digit);
    uint32 value = static_cast<uint32>(
        BnGuess(ca, shifted_b, 0, static_cast<uint64>(kuint32max) + 1));
    q[digit] = value;
    uint32* t = BnMul(shifted_b, value);
    BnSub(ca, t);
    BnFree(t);
    BnFree(shifted_b);
  }

  if (pq)
    *pq = q;
  else
    BnFree(q);
  if (pr)
    *pr = ca;
  else
    BnFree(ca);
}

}  // namespace

crypto::RSAPrivateKey* AndroidRSAPrivateKey(Profile* profile) {
  std::string encoded_key =
      profile->GetPrefs()->GetString(prefs::kDevToolsAdbKey);
  std::string decoded_key;
  scoped_ptr<crypto::RSAPrivateKey> key;
  if (!encoded_key.empty() && base::Base64Decode(encoded_key, &decoded_key)) {
    std::vector<uint8> key_info(decoded_key.begin(), decoded_key.end());
    key.reset(crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(key_info));
  }
  if (!key) {
    key.reset(crypto::RSAPrivateKey::Create(2048));
    std::vector<uint8> key_info;
    if (!key || !key->ExportPrivateKey(&key_info))
      return NULL;

    std::string key_string(key_info.begin(), key_info.end());
    base::Base64Encode(key_string, &encoded_key);
    profile->GetPrefs()->SetString(prefs::kDevToolsAdbKey,
                                   encoded_key);
  }
  return key.release();
}

std::string AndroidRSAPublicKey(crypto::RSAPrivateKey* key) {
  std::vector<uint8> public_key;
  if (!key)
    return kDummyRSAPublicKey;

  key->ExportPublicKey(&public_key);
  std::string asn1(public_key.begin(), public_key.end());

  base::StringPiece pk;
  if (!net::asn1::ExtractSubjectPublicKeyFromSPKI(asn1, &pk))
    return kDummyRSAPublicKey;

  // Skip 10 byte asn1 prefix to the modulus.
  std::vector<uint8> pk_data(pk.data() + 10, pk.data() + pk.length());
  uint32* n = BnNew();
  for (size_t i = 0; i < kRSANumWords; ++i) {
    uint32 t = pk_data[4 * i];
    t = t << 8;
    t += pk_data[4 * i + 1];
    t = t << 8;
    t += pk_data[4 * i + 2];
    t = t << 8;
    t += pk_data[4 * i + 3];
    n[kRSANumWords - i - 1] = t;
  }
  uint64 n0 = n[0];

  RSAPublicKey pkey;
  pkey.len = kRSANumWords;
  pkey.exponent = 65537; // Fixed public exponent
  pkey.n0inv = 0 - ModInverse(n0, GG_LONGLONG(0x100000000));
  if (pkey.n0inv == 0)
    return kDummyRSAPublicKey;

  uint32* r = BnNew();
  r[kRSANumWords * 2] = 1;

  uint32* rr;
  BnDiv(r, n, NULL, &rr);

  for (size_t i = 0; i < kRSANumWords; ++i) {
    pkey.n[i] = n[i];
    pkey.rr[i] = rr[i];
  }

  BnFree(n);
  BnFree(r);
  BnFree(rr);

  std::string output;
  std::string input(reinterpret_cast<char*>(&pkey), sizeof(pkey));
  base::Base64Encode(input, &output);
  return output;
}

std::string AndroidRSASign(crypto::RSAPrivateKey* key,
                           const std::string& body) {
  std::vector<uint8> digest(body.begin(), body.end());
  std::vector<uint8> result;
  if (!crypto::SignatureCreator::Sign(key, vector_as_array(&digest),
                                      digest.size(), &result)) {
    return std::string();
  }
  return std::string(result.begin(), result.end());
}