/contrib/pgcrypto/pgp-pubenc.c

https://gitlab.com/kush/jarulraj-postgresql-cpp · C · 249 lines · 162 code · 33 blank · 54 comment · 27 complexity · 2334c2015b237e1a763b4999ed28487e MD5 · raw file

  1. /*
  2. * pgp-pubenc.c
  3. * Encrypt session key with public key.
  4. *
  5. * Copyright (c) 2005 Marko Kreen
  6. * All rights reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  18. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  21. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27. * SUCH DAMAGE.
  28. *
  29. * contrib/pgcrypto/pgp-pubenc.c
  30. */
  31. #include "postgres.h"
  32. #include "px.h"
  33. #include "pgp.h"
  34. /*
  35. * padded msg: 02 || non-zero pad bytes || 00 || msg
  36. */
  37. static int
  38. pad_eme_pkcs1_v15(uint8 *data, int data_len, int res_len, uint8 **res_p)
  39. {
  40. int res;
  41. uint8 *buf,
  42. *p;
  43. int pad_len = res_len - 2 - data_len;
  44. if (pad_len < 8)
  45. return PXE_BUG;
  46. buf = px_alloc(res_len);
  47. buf[0] = 0x02;
  48. res = px_get_random_bytes(buf + 1, pad_len);
  49. if (res < 0)
  50. {
  51. px_free(buf);
  52. return res;
  53. }
  54. /* pad must not contain zero bytes */
  55. p = buf + 1;
  56. while (p < buf + 1 + pad_len)
  57. {
  58. if (*p == 0)
  59. {
  60. res = px_get_random_bytes(p, 1);
  61. if (res < 0)
  62. break;
  63. }
  64. if (*p != 0)
  65. p++;
  66. }
  67. if (res < 0)
  68. {
  69. px_memset(buf, 0, res_len);
  70. px_free(buf);
  71. return res;
  72. }
  73. buf[pad_len + 1] = 0;
  74. memcpy(buf + pad_len + 2, data, data_len);
  75. *res_p = buf;
  76. return 0;
  77. }
  78. static int
  79. create_secmsg(PGP_Context *ctx, PGP_MPI **msg_p, int full_bytes)
  80. {
  81. uint8 *secmsg;
  82. int res,
  83. i;
  84. unsigned cksum = 0;
  85. int klen = ctx->sess_key_len;
  86. uint8 *padded = NULL;
  87. PGP_MPI *m = NULL;
  88. /* calc checksum */
  89. for (i = 0; i < klen; i++)
  90. cksum += ctx->sess_key[i];
  91. /*
  92. * create "secret message"
  93. */
  94. secmsg = px_alloc(klen + 3);
  95. secmsg[0] = ctx->cipher_algo;
  96. memcpy(secmsg + 1, ctx->sess_key, klen);
  97. secmsg[klen + 1] = (cksum >> 8) & 0xFF;
  98. secmsg[klen + 2] = cksum & 0xFF;
  99. /*
  100. * now create a large integer of it
  101. */
  102. res = pad_eme_pkcs1_v15(secmsg, klen + 3, full_bytes, &padded);
  103. if (res >= 0)
  104. {
  105. /* first byte will be 0x02 */
  106. int full_bits = full_bytes * 8 - 6;
  107. res = pgp_mpi_create(padded, full_bits, &m);
  108. }
  109. if (padded)
  110. {
  111. px_memset(padded, 0, full_bytes);
  112. px_free(padded);
  113. }
  114. px_memset(secmsg, 0, klen + 3);
  115. px_free(secmsg);
  116. if (res >= 0)
  117. *msg_p = m;
  118. return res;
  119. }
  120. static int
  121. encrypt_and_write_elgamal(PGP_Context *ctx, PGP_PubKey *pk, PushFilter *pkt)
  122. {
  123. int res;
  124. PGP_MPI *m = NULL,
  125. *c1 = NULL,
  126. *c2 = NULL;
  127. /* create padded msg */
  128. res = create_secmsg(ctx, &m, pk->pub.elg.p->bytes - 1);
  129. if (res < 0)
  130. goto err;
  131. /* encrypt it */
  132. res = pgp_elgamal_encrypt(pk, m, &c1, &c2);
  133. if (res < 0)
  134. goto err;
  135. /* write out */
  136. res = pgp_mpi_write(pkt, c1);
  137. if (res < 0)
  138. goto err;
  139. res = pgp_mpi_write(pkt, c2);
  140. err:
  141. pgp_mpi_free(m);
  142. pgp_mpi_free(c1);
  143. pgp_mpi_free(c2);
  144. return res;
  145. }
  146. static int
  147. encrypt_and_write_rsa(PGP_Context *ctx, PGP_PubKey *pk, PushFilter *pkt)
  148. {
  149. int res;
  150. PGP_MPI *m = NULL,
  151. *c = NULL;
  152. /* create padded msg */
  153. res = create_secmsg(ctx, &m, pk->pub.rsa.n->bytes - 1);
  154. if (res < 0)
  155. goto err;
  156. /* encrypt it */
  157. res = pgp_rsa_encrypt(pk, m, &c);
  158. if (res < 0)
  159. goto err;
  160. /* write out */
  161. res = pgp_mpi_write(pkt, c);
  162. err:
  163. pgp_mpi_free(m);
  164. pgp_mpi_free(c);
  165. return res;
  166. }
  167. int
  168. pgp_write_pubenc_sesskey(PGP_Context *ctx, PushFilter *dst)
  169. {
  170. int res;
  171. PGP_PubKey *pk = ctx->pub_key;
  172. uint8 ver = 3;
  173. PushFilter *pkt = NULL;
  174. uint8 algo;
  175. if (pk == NULL)
  176. {
  177. px_debug("no pubkey?\n");
  178. return PXE_BUG;
  179. }
  180. algo = pk->algo;
  181. /*
  182. * now write packet
  183. */
  184. res = pgp_create_pkt_writer(dst, PGP_PKT_PUBENCRYPTED_SESSKEY, &pkt);
  185. if (res < 0)
  186. goto err;
  187. res = pushf_write(pkt, &ver, 1);
  188. if (res < 0)
  189. goto err;
  190. res = pushf_write(pkt, pk->key_id, 8);
  191. if (res < 0)
  192. goto err;
  193. res = pushf_write(pkt, &algo, 1);
  194. if (res < 0)
  195. goto err;
  196. switch (algo)
  197. {
  198. case PGP_PUB_ELG_ENCRYPT:
  199. res = encrypt_and_write_elgamal(ctx, pk, pkt);
  200. break;
  201. case PGP_PUB_RSA_ENCRYPT:
  202. case PGP_PUB_RSA_ENCRYPT_SIGN:
  203. res = encrypt_and_write_rsa(ctx, pk, pkt);
  204. break;
  205. }
  206. if (res < 0)
  207. goto err;
  208. /*
  209. * done, signal packet end
  210. */
  211. res = pushf_flush(pkt);
  212. err:
  213. if (pkt)
  214. pushf_free(pkt);
  215. return res;
  216. }