cipher.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. /*
  2. * Copyright (C) 2011-2017 Intel Corporation. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * * Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * * Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in
  12. * the documentation and/or other materials provided with the
  13. * distribution.
  14. * * Neither the name of Intel Corporation nor the names of its
  15. * contributors may be used to endorse or promote products derived
  16. * from this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  21. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  22. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  23. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  24. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  28. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. *
  30. */
  31. /**
  32. * File: cipher.cpp
  33. * Description: Cpp file to wrap cipher related function from IPP for Provision Enclave
  34. *
  35. * Wrap for ipp function like aes-gcm, epid private key parameter f generation.
  36. */
  37. #include "cipher.h"
  38. #include "helper.h"
  39. #include "string.h"
  40. #include "sgx_trts.h"
  41. #include "ipp_wrapper.h"
  42. #include "epid/common/errors.h"
  43. #include "epid/member/api.h"
  44. #include "provision_msg.h"
  45. #include "ae_ipp.h"
  46. #include "util.h"
  47. #include "internal/se_memcpy.h"
  48. #include <stdlib.h>
  49. //Use macro to transform ipp error code into pve error code
  50. #define IPP_ERROR_BREAK(x) if((x) != ippStsNoErr){ret=ipp_error_to_pve_error(x);goto ret_point;}
  51. #define PRIV_F_LOWER_BOUND 1LL
  52. #define PRIV_F_EXTRA_RAND_BYTES 12
  53. #define PRIV_F_RAND_SIZE (PRIV_F_EXTRA_RAND_BYTES+sizeof(FpElemStr))
  54. //Generate a random value for f to be part of EPID private key
  55. //The function will be called in ProvMsg3 of PvE
  56. //f should be a random value between PRIV_F_LOWER_BOUND and p_data-PRIV_F_LOWER_BOUND
  57. //The f is set to PRIV_F_LOWER_BOUND + rand_num % (p_data-2*PRIV_F_LOWER_BOUND+1)
  58. // where the rand_num is big enough so that the output is uniform distributed
  59. //@f, buffer to hold the output value of f, the output will be in big endian
  60. pve_status_t gen_epid_priv_f(
  61. FpElemStr* f)
  62. {
  63. static uint8_t p_data[] = {//Parameter P in Epid2Params in big endian which is order(number of elements) of the ECC group used in EPID2 library
  64. 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xF0, 0xCD,
  65. 0x46, 0xE5, 0xF2, 0x5E, 0xEE, 0x71, 0xA4, 0x9E,
  66. 0x0C, 0xDC, 0x65, 0xFB, 0x12, 0x99, 0x92, 0x1A,
  67. 0xF6, 0x2D, 0x53, 0x6C, 0xD1, 0x0B, 0x50, 0x0D
  68. };
  69. pve_status_t ret = PVEC_SUCCESS;
  70. IppsBigNumState* f_BN = NULL;
  71. IppsBigNumState* p_BN = NULL;
  72. IppsBigNumState* r_BN = NULL;
  73. IppsBigNumState *h_BN = NULL;
  74. IppsBigNumState *d_BN = NULL;
  75. IppStatus ipp_status = ippStsNoErr;
  76. uint8_t f_temp_buf[PRIV_F_RAND_SIZE]; //buffer to hold random bits, it has 96 more bits than f or p
  77. uint64_t lower_bound = PRIV_F_LOWER_BOUND;
  78. uint64_t diff = 2*lower_bound-1;
  79. se_static_assert(sizeof(FpElemStr)%4==0); /*sizeof FpElemStr should be multiple of 4*/
  80. se_static_assert(PRIV_F_RAND_SIZE%4==0); /*the number of bytes of random number should be multiple of 4*/
  81. //First create the mod P which is in little endian
  82. ipp_status = newBN(NULL, sizeof(FpElemStr), &p_BN);//initialize integer buffer
  83. IPP_ERROR_BREAK(ipp_status);
  84. ipp_status = ippsSetOctString_BN(p_data, sizeof(FpElemStr), p_BN);//Input data in Bigendian format
  85. IPP_ERROR_BREAK(ipp_status);
  86. ipp_status = newBN(NULL, sizeof(FpElemStr), &r_BN);//create buffer to hold temp and output result
  87. IPP_ERROR_BREAK(ipp_status);
  88. //initialize a lower bound
  89. ipp_status = newBN(reinterpret_cast<Ipp32u *>(&lower_bound), sizeof(lower_bound), &h_BN);
  90. IPP_ERROR_BREAK(ipp_status);
  91. ipp_status = newBN(reinterpret_cast<Ipp32u *>(&diff), sizeof(diff), &d_BN);//2*PRIV_F_LOWER_BOUND-1
  92. IPP_ERROR_BREAK(ipp_status);
  93. //random generate a number f with 96 bits extra data
  94. // to make sure the output result f%(p_data-(2*PRIV_F_LOWER_BOUND-1)) is uniform distributed
  95. // the extra bits should be at least 80 bits while ipps functions requires the bits to be time of 32 bits
  96. if((ret=pve_rng_generate(static_cast<uint32_t>(PRIV_F_RAND_SIZE*8) , f_temp_buf))!=PVEC_SUCCESS){
  97. goto ret_point;
  98. }
  99. ipp_status = ippsSub_BN(p_BN, d_BN, r_BN);// r = p_data - (2*PRIV_F_LOWER_BOUND-1)
  100. IPP_ERROR_BREAK(ipp_status);
  101. ipp_status = newBN(reinterpret_cast<Ipp32u*>(f_temp_buf), static_cast<uint32_t>(PRIV_F_RAND_SIZE), &f_BN);//create big number by f
  102. IPP_ERROR_BREAK(ipp_status);
  103. ipp_status = ippsMod_BN(f_BN, r_BN, p_BN); //calculate p_BN = f (mod r_BN=(p_data - (2*PRIV_F_LOWER_BOUND-1)))
  104. IPP_ERROR_BREAK(ipp_status);
  105. ipp_status = ippsAdd_BN(p_BN, h_BN, r_BN); //r_BN = f (mod p_data - (2*PRIV_F_LOWER_BOUND-1)) + PRIV_F_LOWER_BOUND;
  106. IPP_ERROR_BREAK(ipp_status);
  107. //output the result and transform it into big endian
  108. ipp_status = ippsGetOctString_BN(reinterpret_cast<uint8_t *>(f), sizeof(FpElemStr),r_BN);
  109. IPP_ERROR_BREAK(ipp_status);
  110. ret_point:
  111. (void)memset_s(f_temp_buf, sizeof(f_temp_buf), 0, sizeof(f_temp_buf));
  112. secure_free_BN(h_BN, sizeof(lower_bound));//free big integer securely (The function will also memset_s the buffer)
  113. secure_free_BN(f_BN, static_cast<uint32_t>(PRIV_F_RAND_SIZE));
  114. secure_free_BN(p_BN, sizeof(FpElemStr));
  115. secure_free_BN(r_BN,sizeof(FpElemStr));
  116. secure_free_BN(d_BN, sizeof(diff));
  117. return ret;
  118. }
  119. pve_status_t pve_aes_gcm_encrypt_init(
  120. const uint8_t *key,
  121. const uint8_t *iv, //input initial vector. randomly generated value and encryption of different msg should use different iv
  122. uint32_t iv_len, //length of initial vector, usually IV_SIZE
  123. const uint8_t *aad,//AAD of AES-GCM, it could be NULL
  124. uint32_t aad_len, //length of bytes of AAD
  125. IppsAES_GCMState **aes_gcm_state, //state buffer to return
  126. uint32_t *state_buffer_size) //return buffer size which will be used by fini function
  127. {
  128. int state_size = 0;
  129. pve_status_t ret = PVEC_SUCCESS;
  130. IppStatus status = ippStsNoErr;
  131. IppsAES_GCMState *p_state = NULL;
  132. status=ippsAES_GCMGetSize(&state_size);
  133. IPP_ERROR_BREAK(status);
  134. p_state = reinterpret_cast<IppsAES_GCMState *>(malloc(state_size));
  135. if(p_state == NULL){
  136. ret = PVEC_MALLOC_ERROR;
  137. goto ret_point;
  138. }
  139. status=ippsAES_GCMInit(key, 16, p_state, state_size);
  140. IPP_ERROR_BREAK(status);
  141. status=ippsAES_GCMStart(iv, iv_len, aad, aad_len, p_state);
  142. IPP_ERROR_BREAK(status);
  143. ret_point:
  144. if(ret != PVEC_SUCCESS && p_state != NULL){
  145. (void)memset_s(p_state, state_size, 0, state_size);
  146. free(p_state);
  147. }else{
  148. *state_buffer_size = state_size;
  149. *aes_gcm_state = p_state;
  150. }
  151. return ret;
  152. }
  153. #define BLOCK_SIZE 64
  154. pve_status_t pve_aes_gcm_encrypt_inplace_update(
  155. IppsAES_GCMState *aes_gcm_state, //pointer to a state
  156. uint8_t *buf, //start address to data before/after encryption
  157. uint32_t buf_len) //length of data
  158. {
  159. uint32_t off = 0;
  160. uint8_t block[BLOCK_SIZE];
  161. IppStatus status = ippStsNoErr;
  162. memset(block, 0, sizeof(block));
  163. //In PvE, we should only use code with buf_len not too large.
  164. //The code in following loop will have integer overflow if buf_len is larger than or equal to 2^32-BLOCK_SIZE. (off+=BLOCK_SIZE)
  165. //For defense in depth, we add extra constrain that buf_len should not be too large
  166. if (buf_len > (1U << 31)){
  167. return PVEC_UNEXPECTED_ERROR;
  168. }
  169. for(off=0;off<buf_len; off+=BLOCK_SIZE){
  170. int enc_len = BLOCK_SIZE;
  171. if(off+BLOCK_SIZE>buf_len)
  172. enc_len = buf_len - off;
  173. if((status =ippsAES_GCMEncrypt(buf+off, block, enc_len, aes_gcm_state))!=ippStsNoErr){
  174. (void)memset_s(block, sizeof(block), 0, BLOCK_SIZE);
  175. return ipp_error_to_pve_error(status);
  176. }
  177. memcpy(buf+off, block, enc_len);
  178. }
  179. (void)memset_s(block,sizeof(block), 0, BLOCK_SIZE );
  180. return PVEC_SUCCESS;
  181. }
  182. pve_status_t pve_aes_gcm_get_mac(IppsAES_GCMState *aes_gcm_state,uint8_t *mac)
  183. {
  184. IppStatus status=ippsAES_GCMGetTag(mac, MAC_SIZE, aes_gcm_state);
  185. return ipp_error_to_pve_error(status);
  186. }
  187. //aes_gcm encryption fini function
  188. void pve_aes_gcm_encrypt_fini(
  189. IppsAES_GCMState *aes_gcm_state, //the state buffer
  190. uint32_t state_buffer_size)//size of the buffer, the function need it to free the memory
  191. {
  192. if(aes_gcm_state!=NULL){
  193. (void)memset_s(aes_gcm_state, state_buffer_size, 0, state_buffer_size);
  194. free(aes_gcm_state);
  195. }
  196. }
  197. pve_status_t ipp_error_to_pve_error(IppStatus status)
  198. {
  199. if(status == ippStsNoErr) return PVEC_SUCCESS;
  200. else if(status == ippStsMemAllocErr||
  201. status == ippStsNoMemErr) return PVEC_MALLOC_ERROR;
  202. else return PVEC_IPP_ERROR;//unknown or unexpected ipp error
  203. }