android_pubkey.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. /*
  2. * Copyright (C) 2016 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include <crypto_utils/android_pubkey.h>
  17. #include <assert.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <openssl/bn.h>
  21. // Better safe than sorry.
  22. #if (ANDROID_PUBKEY_MODULUS_SIZE % 4) != 0
  23. #error RSA modulus size must be multiple of the word size!
  24. #endif
  25. // Size of the RSA modulus in words.
  26. #define ANDROID_PUBKEY_MODULUS_SIZE_WORDS (ANDROID_PUBKEY_MODULUS_SIZE / 4)
  27. // This file implements encoding and decoding logic for Android's custom RSA
  28. // public key binary format. Public keys are stored as a sequence of
  29. // little-endian 32 bit words. Note that Android only supports little-endian
  30. // processors, so we don't do any byte order conversions when parsing the binary
  31. // struct.
  32. typedef struct RSAPublicKey {
  33. // Modulus length. This must be ANDROID_PUBKEY_MODULUS_SIZE.
  34. uint32_t modulus_size_words;
  35. // Precomputed montgomery parameter: -1 / n[0] mod 2^32
  36. uint32_t n0inv;
  37. // RSA modulus as a little-endian array.
  38. uint8_t modulus[ANDROID_PUBKEY_MODULUS_SIZE];
  39. // Montgomery parameter R^2 as a little-endian array of little-endian words.
  40. uint8_t rr[ANDROID_PUBKEY_MODULUS_SIZE];
  41. // RSA modulus: 3 or 65537
  42. uint32_t exponent;
  43. } RSAPublicKey;
  44. // Reverses byte order in |buffer|.
  45. static void reverse_bytes(uint8_t* buffer, size_t size) {
  46. for (size_t i = 0; i < (size + 1) / 2; ++i) {
  47. uint8_t tmp = buffer[i];
  48. buffer[i] = buffer[size - i - 1];
  49. buffer[size - i - 1] = tmp;
  50. }
  51. }
  52. bool android_pubkey_decode(const uint8_t* key_buffer, size_t size, RSA** key) {
  53. const RSAPublicKey* key_struct = (RSAPublicKey*)key_buffer;
  54. bool ret = false;
  55. uint8_t modulus_buffer[ANDROID_PUBKEY_MODULUS_SIZE];
  56. RSA* new_key = RSA_new();
  57. if (!new_key) {
  58. goto cleanup;
  59. }
  60. // Check |size| is large enough and the modulus size is correct.
  61. if (size < sizeof(RSAPublicKey)) {
  62. goto cleanup;
  63. }
  64. if (key_struct->modulus_size_words != ANDROID_PUBKEY_MODULUS_SIZE_WORDS) {
  65. goto cleanup;
  66. }
  67. // Convert the modulus to big-endian byte order as expected by BN_bin2bn.
  68. memcpy(modulus_buffer, key_struct->modulus, sizeof(modulus_buffer));
  69. reverse_bytes(modulus_buffer, sizeof(modulus_buffer));
  70. new_key->n = BN_bin2bn(modulus_buffer, sizeof(modulus_buffer), NULL);
  71. if (!new_key->n) {
  72. goto cleanup;
  73. }
  74. // Read the exponent.
  75. new_key->e = BN_new();
  76. if (!new_key->e || !BN_set_word(new_key->e, key_struct->exponent)) {
  77. goto cleanup;
  78. }
  79. // Note that we don't extract the montgomery parameters n0inv and rr from
  80. // the RSAPublicKey structure. They assume a word size of 32 bits, but
  81. // BoringSSL may use a word size of 64 bits internally, so we're lacking the
  82. // top 32 bits of n0inv in general. For now, we just ignore the parameters
  83. // and have BoringSSL recompute them internally. More sophisticated logic can
  84. // be added here if/when we want the additional speedup from using the
  85. // pre-computed montgomery parameters.
  86. *key = new_key;
  87. ret = true;
  88. cleanup:
  89. if (!ret && new_key) {
  90. RSA_free(new_key);
  91. }
  92. return ret;
  93. }
  94. static bool android_pubkey_encode_bignum(const BIGNUM* num, uint8_t* buffer) {
  95. if (!BN_bn2bin_padded(buffer, ANDROID_PUBKEY_MODULUS_SIZE, num)) {
  96. return false;
  97. }
  98. reverse_bytes(buffer, ANDROID_PUBKEY_MODULUS_SIZE);
  99. return true;
  100. }
  101. bool android_pubkey_encode(const RSA* key, uint8_t* key_buffer, size_t size) {
  102. RSAPublicKey* key_struct = (RSAPublicKey*)key_buffer;
  103. bool ret = false;
  104. BN_CTX* ctx = BN_CTX_new();
  105. BIGNUM* r32 = BN_new();
  106. BIGNUM* n0inv = BN_new();
  107. BIGNUM* rr = BN_new();
  108. if (sizeof(RSAPublicKey) > size ||
  109. RSA_size(key) != ANDROID_PUBKEY_MODULUS_SIZE) {
  110. goto cleanup;
  111. }
  112. // Store the modulus size.
  113. key_struct->modulus_size_words = ANDROID_PUBKEY_MODULUS_SIZE_WORDS;
  114. // Compute and store n0inv = -1 / N[0] mod 2^32.
  115. if (!ctx || !r32 || !n0inv || !BN_set_bit(r32, 32) ||
  116. !BN_mod(n0inv, key->n, r32, ctx) ||
  117. !BN_mod_inverse(n0inv, n0inv, r32, ctx) || !BN_sub(n0inv, r32, n0inv)) {
  118. goto cleanup;
  119. }
  120. key_struct->n0inv = (uint32_t)BN_get_word(n0inv);
  121. // Store the modulus.
  122. if (!android_pubkey_encode_bignum(key->n, key_struct->modulus)) {
  123. goto cleanup;
  124. }
  125. // Compute and store rr = (2^(rsa_size)) ^ 2 mod N.
  126. if (!ctx || !rr || !BN_set_bit(rr, ANDROID_PUBKEY_MODULUS_SIZE * 8) ||
  127. !BN_mod_sqr(rr, rr, key->n, ctx) ||
  128. !android_pubkey_encode_bignum(rr, key_struct->rr)) {
  129. goto cleanup;
  130. }
  131. // Store the exponent.
  132. key_struct->exponent = (uint32_t)BN_get_word(key->e);
  133. ret = true;
  134. cleanup:
  135. BN_free(rr);
  136. BN_free(n0inv);
  137. BN_free(r32);
  138. BN_CTX_free(ctx);
  139. return ret;
  140. }