PageRenderTime 57ms CodeModel.GetById 31ms RepoModel.GetById 1ms app.codeStats 0ms

/release/src/router/tinc/src/gcrypt/rsa.c

https://gitlab.com/envieidoc/tomato
C | 302 lines | 216 code | 60 blank | 26 comment | 51 complexity | d3bcdc21cc4330045057c3d7b568a24a MD5 | raw file
  1. /*
  2. rsa.c -- RSA key handling
  3. Copyright (C) 2007-2012 Guus Sliepen <guus@tinc-vpn.org>
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License along
  13. with this program; if not, write to the Free Software Foundation, Inc.,
  14. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  15. */
  16. #include "system.h"
  17. #include <gcrypt.h>
  18. #include "logger.h"
  19. #include "rsa.h"
  20. // Base64 decoding table
  21. static const uint8_t b64d[128] = {
  22. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  23. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  24. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  25. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  26. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  27. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  28. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  29. 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
  30. 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
  31. 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff,
  32. 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
  33. 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
  34. 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
  35. 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
  36. 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
  37. 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
  38. 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e,
  39. 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24,
  40. 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
  41. 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
  42. 0x31, 0x32, 0x33, 0xff, 0xff, 0xff,
  43. 0xff, 0xff
  44. };
  45. // PEM encoding/decoding functions
  46. static bool pem_decode(FILE *fp, const char *header, uint8_t *buf, size_t size, size_t *outsize) {
  47. bool decode = false;
  48. char line[1024];
  49. uint16_t word = 0;
  50. int shift = 10;
  51. size_t i, j = 0;
  52. while(!feof(fp)) {
  53. if(!fgets(line, sizeof line, fp))
  54. return false;
  55. if(!decode && !strncmp(line, "-----BEGIN ", 11)) {
  56. if(!strncmp(line + 11, header, strlen(header)))
  57. decode = true;
  58. continue;
  59. }
  60. if(decode && !strncmp(line, "-----END", 8)) {
  61. break;
  62. }
  63. if(!decode)
  64. continue;
  65. for(i = 0; line[i] >= ' '; i++) {
  66. if((signed char)line[i] < 0 || b64d[(int)line[i]] == 0xff)
  67. break;
  68. word |= b64d[(int)line[i]] << shift;
  69. shift -= 6;
  70. if(shift <= 2) {
  71. if(j > size) {
  72. errno = ENOMEM;
  73. return false;
  74. }
  75. buf[j++] = word >> 8;
  76. word <<= 8;
  77. shift += 8;
  78. }
  79. }
  80. }
  81. if(outsize)
  82. *outsize = j;
  83. return true;
  84. }
  85. // BER decoding functions
  86. static int ber_read_id(unsigned char **p, size_t *buflen) {
  87. if(*buflen <= 0)
  88. return -1;
  89. if((**p & 0x1f) == 0x1f) {
  90. int id = 0;
  91. bool more;
  92. while(*buflen > 0) {
  93. id <<= 7;
  94. id |= **p & 0x7f;
  95. more = *(*p)++ & 0x80;
  96. (*buflen)--;
  97. if(!more)
  98. break;
  99. }
  100. return id;
  101. } else {
  102. (*buflen)--;
  103. return *(*p)++ & 0x1f;
  104. }
  105. }
  106. static size_t ber_read_len(unsigned char **p, size_t *buflen) {
  107. if(*buflen <= 0)
  108. return -1;
  109. if(**p & 0x80) {
  110. size_t result = 0;
  111. int len = *(*p)++ & 0x7f;
  112. (*buflen)--;
  113. if(len > *buflen)
  114. return 0;
  115. while(len--) {
  116. result <<= 8;
  117. result |= *(*p)++;
  118. (*buflen)--;
  119. }
  120. return result;
  121. } else {
  122. (*buflen)--;
  123. return *(*p)++;
  124. }
  125. }
  126. static bool ber_read_sequence(unsigned char **p, size_t *buflen, size_t *result) {
  127. int tag = ber_read_id(p, buflen);
  128. size_t len = ber_read_len(p, buflen);
  129. if(tag == 0x10) {
  130. if(result)
  131. *result = len;
  132. return true;
  133. } else {
  134. return false;
  135. }
  136. }
  137. static bool ber_read_mpi(unsigned char **p, size_t *buflen, gcry_mpi_t *mpi) {
  138. int tag = ber_read_id(p, buflen);
  139. size_t len = ber_read_len(p, buflen);
  140. gcry_error_t err = 0;
  141. if(tag != 0x02 || len > *buflen)
  142. return false;
  143. if(mpi)
  144. err = gcry_mpi_scan(mpi, GCRYMPI_FMT_USG, *p, len, NULL);
  145. *p += len;
  146. *buflen -= len;
  147. return mpi ? !err : true;
  148. }
  149. bool rsa_set_hex_public_key(rsa_t *rsa, char *n, char *e) {
  150. gcry_error_t err = 0;
  151. err = gcry_mpi_scan(&rsa->n, GCRYMPI_FMT_HEX, n, 0, NULL)
  152. ?: gcry_mpi_scan(&rsa->e, GCRYMPI_FMT_HEX, e, 0, NULL);
  153. if(err) {
  154. logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading RSA public key: %s", gcry_strerror(errno));
  155. return false;
  156. }
  157. return true;
  158. }
  159. bool rsa_set_hex_private_key(rsa_t *rsa, char *n, char *e, char *d) {
  160. gcry_error_t err = 0;
  161. err = gcry_mpi_scan(&rsa->n, GCRYMPI_FMT_HEX, n, 0, NULL)
  162. ?: gcry_mpi_scan(&rsa->e, GCRYMPI_FMT_HEX, e, 0, NULL)
  163. ?: gcry_mpi_scan(&rsa->d, GCRYMPI_FMT_HEX, d, 0, NULL);
  164. if(err) {
  165. logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading RSA public key: %s", gcry_strerror(errno));
  166. return false;
  167. }
  168. return true;
  169. }
  170. // Read PEM RSA keys
  171. bool rsa_read_pem_public_key(rsa_t *rsa, FILE *fp) {
  172. uint8_t derbuf[8096], *derp = derbuf;
  173. size_t derlen;
  174. if(!pem_decode(fp, "RSA PUBLIC KEY", derbuf, sizeof derbuf, &derlen)) {
  175. logger(DEBUG_ALWAYS, LOG_ERR, "Unable to read RSA public key: %s", strerror(errno));
  176. return NULL;
  177. }
  178. if(!ber_read_sequence(&derp, &derlen, NULL)
  179. || !ber_read_mpi(&derp, &derlen, &rsa->n)
  180. || !ber_read_mpi(&derp, &derlen, &rsa->e)
  181. || derlen) {
  182. logger(DEBUG_ALWAYS, LOG_ERR, "Error while decoding RSA public key");
  183. return NULL;
  184. }
  185. return true;
  186. }
  187. bool rsa_read_pem_private_key(rsa_t *rsa, FILE *fp) {
  188. uint8_t derbuf[8096], *derp = derbuf;
  189. size_t derlen;
  190. if(!pem_decode(fp, "RSA PRIVATE KEY", derbuf, sizeof derbuf, &derlen)) {
  191. logger(DEBUG_ALWAYS, LOG_ERR, "Unable to read RSA private key: %s", strerror(errno));
  192. return NULL;
  193. }
  194. if(!ber_read_sequence(&derp, &derlen, NULL)
  195. || !ber_read_mpi(&derp, &derlen, NULL)
  196. || !ber_read_mpi(&derp, &derlen, &rsa->n)
  197. || !ber_read_mpi(&derp, &derlen, &rsa->e)
  198. || !ber_read_mpi(&derp, &derlen, &rsa->d)
  199. || !ber_read_mpi(&derp, &derlen, NULL) // p
  200. || !ber_read_mpi(&derp, &derlen, NULL) // q
  201. || !ber_read_mpi(&derp, &derlen, NULL)
  202. || !ber_read_mpi(&derp, &derlen, NULL)
  203. || !ber_read_mpi(&derp, &derlen, NULL) // u
  204. || derlen) {
  205. logger(DEBUG_ALWAYS, LOG_ERR, "Error while decoding RSA private key");
  206. return NULL;
  207. }
  208. return true;
  209. }
  210. size_t rsa_size(rsa_t *rsa) {
  211. return (gcry_mpi_get_nbits(rsa->n) + 7) / 8;
  212. }
  213. /* Well, libgcrypt has functions to handle RSA keys, but they suck.
  214. * So we just use libgcrypt's mpi functions, and do the math ourselves.
  215. */
  216. // TODO: get rid of this macro, properly clean up gcry_ structures after use
  217. #define check(foo) { gcry_error_t err = (foo); if(err) {logger(DEBUG_ALWAYS, LOG_ERR, "gcrypt error %s/%s at %s:%d", gcry_strsource(err), gcry_strerror(err), __FILE__, __LINE__); return false; }}
  218. bool rsa_public_encrypt(rsa_t *rsa, void *in, size_t len, void *out) {
  219. gcry_mpi_t inmpi;
  220. check(gcry_mpi_scan(&inmpi, GCRYMPI_FMT_USG, in, len, NULL));
  221. gcry_mpi_t outmpi = gcry_mpi_new(len * 8);
  222. gcry_mpi_powm(outmpi, inmpi, rsa->e, rsa->n);
  223. int pad = len - (gcry_mpi_get_nbits(outmpi) + 7) / 8;
  224. while(pad--)
  225. *(char *)out++ = 0;
  226. check(gcry_mpi_print(GCRYMPI_FMT_USG, out,len, NULL, outmpi));
  227. return true;
  228. }
  229. bool rsa_private_decrypt(rsa_t *rsa, void *in, size_t len, void *out) {
  230. gcry_mpi_t inmpi;
  231. check(gcry_mpi_scan(&inmpi, GCRYMPI_FMT_USG, in, len, NULL));
  232. gcry_mpi_t outmpi = gcry_mpi_new(len * 8);
  233. gcry_mpi_powm(outmpi, inmpi, rsa->d, rsa->n);
  234. int pad = len - (gcry_mpi_get_nbits(outmpi) + 7) / 8;
  235. while(pad--)
  236. *(char *)out++ = 0;
  237. check(gcry_mpi_print(GCRYMPI_FMT_USG, out,len, NULL, outmpi));
  238. return true;
  239. }