File: android_rsa.cc

package info (click to toggle)
chromium 140.0.7339.127-1
  • links: PTS, VCS
  • area: main
  • in suites: forky
  • size: 6,192,880 kB
  • sloc: cpp: 35,093,808; ansic: 7,161,670; javascript: 4,199,694; python: 1,441,797; asm: 949,904; xml: 747,503; pascal: 187,748; perl: 88,691; sh: 88,248; objc: 79,953; sql: 52,714; cs: 44,599; fortran: 24,137; makefile: 22,114; tcl: 15,277; php: 13,980; yacc: 9,000; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (172 lines) | stat: -rw-r--r-- 6,195 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/devtools/device/usb/android_rsa.h"

#include <stddef.h>
#include <stdint.h>

#include <array>
#include <string_view>

#include "base/base64.h"
#include "base/check.h"
#include "base/containers/span.h"
#include "base/containers/span_writer.h"
#include "base/numerics/byte_conversions.h"
#include "base/numerics/safe_conversions.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "components/sync_preferences/pref_service_syncable.h"
#include "crypto/keypair.h"
#include "third_party/boringssl/src/include/openssl/bn.h"
#include "third_party/boringssl/src/include/openssl/evp.h"
#include "third_party/boringssl/src/include/openssl/rsa.h"

namespace {

// The Android RSA format is fixed-width and can only represent 2048-bit RSA.
constexpr size_t kRSAModulusBytes = 2048 / 8;

// The Android RSA format is 524 bytes in total:
// - 4 bytes, little-endian: length of n in number of u32s, must be 64
// - 4 bytes, little-endian: precomputed -1 / n[0] mod 2^32 (unused in modern
//   Android)
// - 256 bytes, little-endian: modulus
// - 256 bytes, little-endian: precomputed R^2 (unused in modern Android)
// - 4 bytes, little-endian: public exponent
constexpr size_t kAndroidRSASize = 524;

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

  while (b > 0) {
    uint64_t q = a / b;
    uint64_t 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_t ModInverse2_32(uint32_t a) {
  CHECK_EQ(a & 1u, 1u);  // a must be odd
  uint64_t d, x, y;
  ExtendedEuclid(a, 0x100000000, &x, &y, &d);
  CHECK_EQ(d, 1u);  // If a is odd, there is an inverse.
  return static_cast<uint32_t>(x);
}

bool WriteLittleEndianBignum(const BIGNUM* bn, base::span<uint8_t> out) {
  return BN_bn2le_padded(out.data(), out.size(), bn);
}

}  // namespace

crypto::keypair::PrivateKey AndroidRSAPrivateKey(Profile* profile) {
  std::string encoded_key =
      profile->GetPrefs()->GetString(prefs::kDevToolsAdbKey);
  std::string decoded_key;
  std::optional<crypto::keypair::PrivateKey> key;
  if (!encoded_key.empty() && base::Base64Decode(encoded_key, &decoded_key)) {
    key = crypto::keypair::PrivateKey::FromPrivateKeyInfo(
        base::as_byte_span(decoded_key));
  }
  if (!key) {
    key = crypto::keypair::PrivateKey::GenerateRsa2048();
    profile->GetPrefs()->SetString(prefs::kDevToolsAdbKey,
                                   base::Base64Encode(key->ToPrivateKeyInfo()));
  }
  return *key;
}

std::optional<std::string> AndroidRSAPublicKey(
    crypto::keypair::PrivateKey key) {
  // Assemble Android's custom RSA format. This format dates to when Android was
  // using a custom "minicrypt" RSA implementation and was just minicrypt's
  // in-memory representation. The format assumes 2048-bit RSA (up to byte
  // precision) and also includes precomputed information for Montgomery
  // reduction with 32-bit words.
  //
  // This precomputed information no longer makes sense with modern 64-bit
  // processors, and does not contain quite enough information for 64-bit
  // Montgomery reduction. Starting Android O, it no longer looks at it at all.
  // See https://r.android.com/212780 and https://r.android.com/212781.
  //
  // However, that information is still hashed into existing ADB key
  // fingerprints, so continue computing them to keep the fingerprint stable.
  RSA* rsa = EVP_PKEY_get0_RSA(key.key());
  uint64_t e;
  if (RSA_size(rsa) != kRSAModulusBytes ||  //
      !BN_get_u64(RSA_get0_e(rsa), &e) ||
      !base::IsValueInRangeForNumericType<uint32_t>(e)) {
    return std::nullopt;
  }

  std::array<uint8_t, kAndroidRSASize> out;
  auto writer = base::SpanWriter(base::span(out));
  writer.WriteU32LittleEndian(kRSAModulusBytes / 4);
  // Reserve space for ninv. We'll compute it after we've written N.
  auto ninv = *writer.Skip<4>();
  auto n = *writer.Skip<kRSAModulusBytes>();
  CHECK(WriteLittleEndianBignum(RSA_get0_n(rsa), n));
  // Fill in RR, or 2^4096 mod N.
  bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
  bssl::UniquePtr<BIGNUM> rr(BN_new());
  CHECK(BN_set_bit(rr.get(), 4096));
  CHECK(BN_mod(rr.get(), rr.get(), RSA_get0_n(rsa), ctx.get()));
  CHECK(WriteLittleEndianBignum(rr.get(), *writer.Skip<kRSAModulusBytes>()));
  writer.WriteU32LittleEndian(base::checked_cast<uint32_t>(e));

  // Compute ninv = -1 / n[0] mod 2^32. This value being 32-bit makes the
  // pre-computed Montgomery values useless on a modern system. A 64-bit
  // Montgomery reduction needs it mod 2^64. But we compute it anyway. The mod
  // inverse cannot fail because BoringSSL will ensure N is odd.
  uint32_t n0 = base::U32FromLittleEndian(n.first<4>());
  ninv.copy_from(base::U32ToLittleEndian(0u - ModInverse2_32(n0)));

  // Make sure we've written everything.
  CHECK_EQ(writer.remaining(), 0u);
  return base::Base64Encode(out);
}

std::string AndroidRSASign(crypto::keypair::PrivateKey key,
                           const std::string& body) {
  RSA* rsa = EVP_PKEY_get0_RSA(key.key());
  if (!rsa) {
    return std::string();
  }

  std::string result(RSA_size(rsa), 0);
  unsigned int len = 0;

  auto body_bytes = base::as_byte_span(body);
  auto result_bytes = base::as_writable_byte_span(result);

  // The ADB protocol requires us to sign a 20-byte challenge, and assumes the
  // challenge is a pre-hashed SHA-1 digest, although there is no guarantee that
  // that is true, and signs it without further hashing. In general this is not
  // a secure signature scheme and should not be used elsewhere.
  if (!RSA_sign(NID_sha1, body_bytes.data(), body_bytes.size(),
                result_bytes.data(), &len, rsa)) {
    return std::string();
  }
  result.resize(len);
  return result;
}