Rev

Rev 3345 | Details | Compare with Previous | Last modification | View Log | SVN | Bug Tracker

Rev Author Line No. Line
3342 garciay 1
/*!
2
 * \file      security_ecc.cc
3
 * \brief     Source file for Elliptic Curve Cryptography.
4
 * \author    ETSI STF525
5
 * \copyright ETSI Copyright Notification
6
 *            No part may be reproduced except as authorized by written permission.
7
 *            The copyright and the foregoing restriction extend to reproduction in all media.
8
 *            All rights reserved.
9
 * \version   0.1
10
 */
3343 garciay 11
#include <TTCN3.hh>
12
 
2955 garciay 13
#include <openssl/ecdsa.h>
3100 garciay 14
#include <openssl/rand.h>
2955 garciay 15
 
3117 garciay 16
#include "hmac.hh"
3115 garciay 17
#include "security_ecc.hh"
2955 garciay 18
 
3101 garciay 19
#include "loggers.hh"
2955 garciay 20
 
3177 garciay 21
security_ecc::security_ecc(const ec_elliptic_curves p_elliptic_curve): _elliptic_curve(p_elliptic_curve), _encryption_algotithm(encryption_algotithm::aes_128_ccm), _ec_key(nullptr), _ec_group(nullptr), _bn_ctx(nullptr), _pri_key(), _pub_key_x(), _pub_key_y(), _pub_key_compressed(), _pub_key_compressed_mode{ecc_compressed_mode::compressed_y_0}, _secret_key(), _enc_key_x(), _enc_key_y(), _sym_key(), _nonce(), _tag() {
3115 garciay 22
  loggers::get_instance().log(">>> security_ecc::security_ecc: %d", static_cast<int>(p_elliptic_curve));
2955 garciay 23
 
2961 garciay 24
  const int result = init();
25
  if (result == -1) {
3115 garciay 26
    loggers::get_instance().error("security_ecc::security_ecc: Unsupported elliptic_curve %d", _elliptic_curve);
2961 garciay 27
  }
2955 garciay 28
} // End of constructor
29
 
3342 garciay 30
security_ecc::security_ecc(const ec_elliptic_curves p_elliptic_curve, const OCTETSTRING& p_private_key): _elliptic_curve(p_elliptic_curve), _encryption_algotithm(encryption_algotithm::aes_128_ccm), _ec_key(nullptr), _ec_group(nullptr), _bn_ctx(nullptr), _pri_key(p_private_key), _pub_key_x(), _pub_key_y(), _pub_key_compressed(), _pub_key_compressed_mode{ecc_compressed_mode::compressed_y_0}, _secret_key(), _enc_key_x(), _enc_key_y(), _sym_key(), _nonce(), _tag() {
3115 garciay 31
  loggers::get_instance().log(">>> security_ecc::security_ecc (1): %d", static_cast<int>(p_elliptic_curve));
2955 garciay 32
 
2967 garciay 33
  // Sanity checks
34
  if ((_elliptic_curve == ec_elliptic_curves::nist_p_256) || (_elliptic_curve == ec_elliptic_curves::brainpool_p_256_r1)) {
3342 garciay 35
    if (p_private_key.lengthof() != 32) {
3177 garciay 36
      loggers::get_instance().error("security_ecc::security_ecc (1): Invalid public keys size");
2967 garciay 37
    }
38
  } else if (_elliptic_curve == ec_elliptic_curves::brainpool_p_384_r1) {
3342 garciay 39
    if ((p_private_key.lengthof() != 48)) {
3177 garciay 40
      loggers::get_instance().error("security_ecc::security_ecc (1): Invalid public keys size");
2967 garciay 41
    }
42
  }
43
 
2961 garciay 44
  int result = init();
45
  if (result == -1) {
3177 garciay 46
    loggers::get_instance().error("security_ecc::security_ecc (1): Unsupported elliptic_curve %d", _elliptic_curve);
2961 garciay 47
  }
3177 garciay 48
  ::EC_KEY_set_conv_form(_ec_key, POINT_CONVERSION_UNCOMPRESSED);
2955 garciay 49
 
50
  // Build private key
3299 garciay 51
  BIGNUM* p = ::BN_new();
3342 garciay 52
  ::BN_bin2bn(static_cast<const unsigned char*>(_pri_key), _pri_key.lengthof(), p);
2955 garciay 53
  // Build public keys
54
  EC_POINT* ec_point = ::EC_POINT_new(_ec_group);
3342 garciay 55
  ::EC_POINT_mul(_ec_group, ec_point, p, nullptr, nullptr, _bn_ctx);
2955 garciay 56
  // Set private key
3299 garciay 57
  ::EC_KEY_set_private_key(_ec_key, p);
2955 garciay 58
  if (::EC_KEY_check_key(_ec_key) != 0) {
3343 garciay 59
    ::BN_clear_free(p);
3115 garciay 60
    loggers::get_instance().error("security_ecc::security_ecc (1): Invalid private key");
2955 garciay 61
  }
3299 garciay 62
  ::BN_clear_free(p);
63
  p = nullptr;
2955 garciay 64
  // Private key is correct, set public keys
65
  ::EC_KEY_set_public_key(_ec_key, ec_point);
66
 
3299 garciay 67
  BIGNUM* xy = ::BN_new();
68
  ::EC_POINT_point2bn(_ec_group, ec_point, POINT_CONVERSION_UNCOMPRESSED, xy, _bn_ctx);
69
  if (BN_num_bytes(xy) == 0) {
3343 garciay 70
    ::BN_clear_free(xy);
3177 garciay 71
    loggers::get_instance().error("security_ecc::security_ecc (1): Failed to generate xy coordinates, check algorithms");
72
  }
3299 garciay 73
  loggers::get_instance().log("security_ecc::security_ecc (1): xy length: %d", BN_num_bytes(xy));
3342 garciay 74
  OCTETSTRING v = int2oct(0, BN_num_bytes(xy));
75
  ::BN_bn2bin(xy, (unsigned char*)static_cast<const unsigned char*>(v));
76
  if ((v.lengthof() % 2) != 0) {
3177 garciay 77
    // Remove first byte
3342 garciay 78
    loggers::get_instance().log_msg("security_ecc::security_ecc (1): Complete xy=", v);
79
    v = OCTETSTRING(v.lengthof() - 1, 1 + static_cast<const unsigned char*>(v));
3177 garciay 80
  }
3299 garciay 81
  ::BN_clear_free(xy);
82
  xy = nullptr;
83
 
3342 garciay 84
  loggers::get_instance().log_msg("security_ecc::security_ecc (1): xy=", v);
85
  const int l = v.lengthof() / 2;
86
  _pub_key_x = OCTETSTRING(l, static_cast<const unsigned char*>(v));
87
  _pub_key_y = OCTETSTRING(l, l + static_cast<const unsigned char*>(v));
3177 garciay 88
 
89
  // Compressed
3342 garciay 90
  int len = ::EC_POINT_point2oct(_ec_group, ec_point, POINT_CONVERSION_COMPRESSED, nullptr, 0, _bn_ctx);
3177 garciay 91
  if (len == 0) {
92
    loggers::get_instance().warning("security_ecc::security_ecc (1): Failed to generate x_coordinate compressed key");
3342 garciay 93
    _pub_key_compressed = OCTETSTRING(0, nullptr);
94
  } else {
95
    _pub_key_compressed = int2oct(0, len);
96
    if (::EC_POINT_point2oct(_ec_group, ec_point, POINT_CONVERSION_COMPRESSED, (unsigned char*)static_cast<const unsigned char*>(_pub_key_compressed), len, _bn_ctx) == 0) {
97
      loggers::get_instance().warning("security_ecc::security_ecc (1): Failed to generate x_coordinate compressed key");
98
      _pub_key_compressed = OCTETSTRING(0, nullptr);
99
    } else { // Remove first byte
100
      loggers::get_instance().log_msg("security_ecc::security_ecc (1): Complete _pub_key_compressed=", _pub_key_compressed);
101
      _pub_key_compressed_mode = ((v[0].get_octet() & 0x01) == 0x00) ? ecc_compressed_mode::compressed_y_0 : ecc_compressed_mode::compressed_y_1;
3343 garciay 102
      _pub_key_compressed = OCTETSTRING(_pub_key_compressed.lengthof() - 1, 1 + static_cast<const unsigned char*>(_pub_key_compressed));
3342 garciay 103
    }
3177 garciay 104
  }
2955 garciay 105
  ::EC_POINT_free(ec_point);
3342 garciay 106
  loggers::get_instance().log_msg("security_ecc::security_ecc (1): _pub_key_x=", _pub_key_x);
107
  loggers::get_instance().log_msg("security_ecc::security_ecc (1): _pub_key_y=", _pub_key_y);
108
  loggers::get_instance().log_msg("security_ecc::security_ecc (1): _pub_key_compressed=", _pub_key_compressed);
3182 garciay 109
  loggers::get_instance().log("security_ecc::security_ecc (1): _pub_key_compressed_mode=%d", _pub_key_compressed_mode);
2955 garciay 110
} // End of constructor
111
 
3342 garciay 112
security_ecc::security_ecc(const ec_elliptic_curves p_elliptic_curve, const OCTETSTRING& p_public_key_x, const OCTETSTRING& p_public_key_y): _elliptic_curve(p_elliptic_curve), _encryption_algotithm(encryption_algotithm::aes_128_ccm), _ec_key(nullptr), _ec_group(nullptr), _bn_ctx(nullptr), _pri_key(), _pub_key_x(p_public_key_x), _pub_key_y(p_public_key_y), _pub_key_compressed(), _pub_key_compressed_mode{ecc_compressed_mode::compressed_y_0}, _secret_key(), _enc_key_x(), _enc_key_y(), _sym_key(), _nonce(), _tag() {
3115 garciay 113
  loggers::get_instance().log(">>> security_ecc::security_ecc (2): %d", static_cast<int>(p_elliptic_curve));
2955 garciay 114
 
2967 garciay 115
  // Sanity checks
116
  if ((_elliptic_curve == ec_elliptic_curves::nist_p_256) || (_elliptic_curve == ec_elliptic_curves::brainpool_p_256_r1)) {
3342 garciay 117
    if ((p_public_key_x.lengthof() != 32) || (p_public_key_y.lengthof() != 32)) {
3177 garciay 118
      loggers::get_instance().error("security_ecc::security_ecc (2): Invalid public keys size");
2967 garciay 119
    }
120
  } else if (_elliptic_curve == ec_elliptic_curves::brainpool_p_384_r1) {
3342 garciay 121
    if ((p_public_key_x.lengthof() != 48) || (p_public_key_y.lengthof() != 48)) {
3177 garciay 122
      loggers::get_instance().error("security_ecc::security_ecc (2): Invalid public keys size");
2967 garciay 123
    }
124
  }
125
 
2961 garciay 126
  int result = init();
127
  if (result == -1) {
3177 garciay 128
    loggers::get_instance().error("security_ecc::security_ecc (2): Unsupported elliptic_curve %d", _elliptic_curve);
2961 garciay 129
  }
3177 garciay 130
  ::EC_KEY_set_conv_form(_ec_key, POINT_CONVERSION_UNCOMPRESSED);
2955 garciay 131
 
132
  // Set public key
3299 garciay 133
  BIGNUM* x = ::BN_new();
3342 garciay 134
  ::BN_bin2bn(static_cast<const unsigned char*>(_pub_key_x), _pub_key_x.lengthof(), x);
3299 garciay 135
  BIGNUM* y = ::BN_new();
3342 garciay 136
  ::BN_bin2bn(static_cast<const unsigned char*>(_pub_key_y), _pub_key_y.lengthof(), y);
2955 garciay 137
  EC_POINT* ec_point = ::EC_POINT_new(_ec_group);
138
  result = 0;
139
  switch (_elliptic_curve) {
2961 garciay 140
  case ec_elliptic_curves::nist_p_256: // Use primary
141
    // No break;
142
  case ec_elliptic_curves::brainpool_p_256_r1:
143
    // No break;
144
  case ec_elliptic_curves::brainpool_p_384_r1:
3299 garciay 145
    result = ::EC_POINT_set_affine_coordinates_GFp(_ec_group, ec_point, x, y, _bn_ctx); // Use primary elliptic curve
2955 garciay 146
    break;
2961 garciay 147
  default: // Use Binary
3299 garciay 148
    result = ::EC_POINT_set_affine_coordinates_GF2m(_ec_group, ec_point, x, y, _bn_ctx);
2955 garciay 149
  } // End of 'switch' statement
150
  if (result == 0) {
3343 garciay 151
    ::BN_clear_free(x);
152
    ::BN_clear_free(y);
3177 garciay 153
    loggers::get_instance().error("security_ecc::security_ecc (2): Failed to get coordinates");
2955 garciay 154
  }
3299 garciay 155
  ::BN_clear_free(x); x = nullptr;
156
  ::BN_clear_free(y); y = nullptr;
157
 
2955 garciay 158
  ::EC_KEY_set_public_key(_ec_key, ec_point);
3177 garciay 159
 
160
  // Compressed
3342 garciay 161
  int len = ::EC_POINT_point2oct(_ec_group, ec_point, POINT_CONVERSION_COMPRESSED, nullptr, 0, _bn_ctx);
3177 garciay 162
  if (len == 0) {
163
    loggers::get_instance().warning("security_ecc::security_ecc (2): Failed to generate x_coordinate compressed key");
164
  }
3342 garciay 165
  _pub_key_compressed = int2oct(0, len);
166
  if (::EC_POINT_point2oct(_ec_group, ec_point, POINT_CONVERSION_COMPRESSED, (unsigned char *)static_cast<const unsigned char*>(_pub_key_compressed), len, _bn_ctx) == 0) {
3177 garciay 167
    loggers::get_instance().warning("security_ecc::security_ecc (2): Failed to generate x_coordinate compressed key");
3342 garciay 168
    _pub_key_compressed = OCTETSTRING(0, nullptr);
3177 garciay 169
  } else { // Remove first byte
3342 garciay 170
    loggers::get_instance().log_msg("security_ecc::security_ecc (2): Complete _pub_key_compressed=", _pub_key_compressed);
171
    _pub_key_compressed = OCTETSTRING(_pub_key_compressed.lengthof() -1, 1 + static_cast<const unsigned char*>(_pub_key_compressed));
3177 garciay 172
  }
2955 garciay 173
  ::EC_POINT_free(ec_point);
3342 garciay 174
  loggers::get_instance().log_msg("security_ecc::security_ecc (2): _pub_key_x=", _pub_key_x);
175
  loggers::get_instance().log_msg("security_ecc::security_ecc (2): _pub_key_y=", _pub_key_y);
176
  loggers::get_instance().log_msg("security_ecc::security_ecc (2): _pub_key_compressed=", _pub_key_compressed);
3256 garciay 177
  loggers::get_instance().log("security_ecc::security_ecc (2): _pub_key_compressed_mode=%d", _pub_key_compressed_mode);
2955 garciay 178
} // End of constructor
179
 
3342 garciay 180
security_ecc::security_ecc(const ec_elliptic_curves p_elliptic_curve, const OCTETSTRING& p_public_key_compressed, const ecc_compressed_mode p_compressed_mode): _elliptic_curve(p_elliptic_curve), _encryption_algotithm(encryption_algotithm::aes_128_ccm), _ec_key(nullptr), _ec_group(nullptr), _bn_ctx(nullptr), _pri_key(), _pub_key_x(), _pub_key_y(), _pub_key_compressed(p_public_key_compressed), _pub_key_compressed_mode{p_compressed_mode}, _secret_key(), _enc_key_x(), _enc_key_y(), _sym_key(), _nonce(), _tag() {
3177 garciay 181
  loggers::get_instance().log(">>> security_ecc::security_ecc (3): %d", static_cast<int>(p_elliptic_curve));
182
 
183
  // Sanity checks
184
  if ((_elliptic_curve == ec_elliptic_curves::nist_p_256) || (_elliptic_curve == ec_elliptic_curves::brainpool_p_256_r1)) {
3342 garciay 185
    if (p_public_key_compressed.lengthof() != 32) {
3177 garciay 186
      loggers::get_instance().error("security_ecc::security_ecc (3): Invalid public keys size");
187
    }
188
  } else if (_elliptic_curve == ec_elliptic_curves::brainpool_p_384_r1) {
3342 garciay 189
    if (p_public_key_compressed.lengthof() != 48) {
3177 garciay 190
      loggers::get_instance().error("security_ecc::security_ecc (3): Invalid public keys size");
191
    }
192
  }
193
 
194
  int result = init();
195
  if (result == -1) {
196
    loggers::get_instance().error("security_ecc::security_ecc (3): Unsupported elliptic_curve %d", _elliptic_curve);
197
  }
198
  ::EC_KEY_set_conv_form(_ec_key, POINT_CONVERSION_UNCOMPRESSED);
199
 
200
  // Set public key
3299 garciay 201
  BIGNUM* compressed_key = ::BN_new();
3342 garciay 202
  ::BN_bin2bn(static_cast<const unsigned char*>(_pub_key_compressed), _pub_key_compressed.lengthof(), compressed_key);
3177 garciay 203
  EC_POINT* ec_point = ::EC_POINT_new(_ec_group);
204
  result = 0;
205
  switch (_elliptic_curve) {
206
  case ec_elliptic_curves::nist_p_256: // Use primary
207
    // No break;
208
  case ec_elliptic_curves::brainpool_p_256_r1:
209
    // No break;
210
  case ec_elliptic_curves::brainpool_p_384_r1:
3299 garciay 211
    result = ::EC_POINT_set_compressed_coordinates_GFp(_ec_group, ec_point, compressed_key, (p_compressed_mode == ecc_compressed_mode::compressed_y_1) ? 1 : 0, _bn_ctx); // Use primary elliptic curve
3177 garciay 212
    break;
213
  default: // Use Binary
3299 garciay 214
    result = ::EC_POINT_set_compressed_coordinates_GF2m(_ec_group, ec_point, compressed_key, (p_compressed_mode == ecc_compressed_mode::compressed_y_1) ? 1 : 0, _bn_ctx);
3177 garciay 215
  } // End of 'switch' statement
3299 garciay 216
  BN_clear_free(compressed_key);
217
  compressed_key = nullptr;
218
 
3177 garciay 219
  if (result == 0) {
220
    loggers::get_instance().error("security_ecc::security_ecc (3): Failed to get coordinates");
221
  } else if (::EC_POINT_is_on_curve(_ec_group, ec_point, _bn_ctx) == 0) {
222
    loggers::get_instance().error("security_ecc::security_ecc (3): Point Y0 is not on the curve");
223
  }
224
 
225
  // Set public keys
3299 garciay 226
  BIGNUM* xy = ::BN_new();
227
  ::EC_POINT_point2bn(_ec_group, ec_point, POINT_CONVERSION_UNCOMPRESSED, xy, _bn_ctx);
228
  if (BN_num_bytes(xy) == 0) {
3343 garciay 229
    ::BN_clear_free(xy);
3177 garciay 230
    loggers::get_instance().error("security_ecc::security_ecc (3): Failed to generate xy coordinates, check algorithms");
231
  }
3299 garciay 232
  loggers::get_instance().log("security_ecc::security_ecc (3): xy length: %d", BN_num_bytes(xy));
3177 garciay 233
  ::EC_KEY_set_public_key(_ec_key, ec_point);
234
  // Generate X, Y coordinates
3342 garciay 235
  OCTETSTRING v = int2oct(0, BN_num_bytes(xy));
236
  ::BN_bn2bin(xy, (unsigned char*)static_cast<const unsigned char*>(v));
3299 garciay 237
  ::BN_clear_free(xy);
238
  xy = nullptr;
3342 garciay 239
  if ((v.lengthof() % 2) != 0) { // TODO Check alse xy[0] == 0x04
3177 garciay 240
    // Remove first byte
3342 garciay 241
    loggers::get_instance().log_msg("security_ecc::security_ecc (3): Complete xy=", v);
242
    v = OCTETSTRING(v.lengthof() -1, 1 + static_cast<const unsigned char*>(v));
3177 garciay 243
  }
3342 garciay 244
  loggers::get_instance().log_msg("security_ecc::security_ecc (3): xy=", v);
245
  const int l = v.lengthof() / 2;
246
  _pub_key_x = OCTETSTRING(l, static_cast<const unsigned char*>(v));
247
  _pub_key_y = OCTETSTRING(l, l + static_cast<const unsigned char*>(v));
3177 garciay 248
  ::EC_POINT_free(ec_point);
249
 
3342 garciay 250
  loggers::get_instance().log_msg("security_ecc::security_ecc (3): _pub_key_x=", _pub_key_x);
251
  loggers::get_instance().log_msg("security_ecc::security_ecc (3): _pub_key_y=", _pub_key_y);
252
  loggers::get_instance().log_msg("security_ecc::security_ecc (3): _pub_key_compressed=", _pub_key_compressed);
3182 garciay 253
  loggers::get_instance().log("security_ecc::security_ecc (3): _pub_key_compressed_mode=%d", _pub_key_compressed_mode);
3177 garciay 254
} // End of constructor
255
 
3115 garciay 256
security_ecc::~security_ecc() {
257
  loggers::get_instance().log(">>> security_ecc::~security_ecc");
2962 garciay 258
 
2955 garciay 259
  if(_ec_key != nullptr) {
260
    ::EC_KEY_free(_ec_key);
261
  }
2962 garciay 262
  if (_bn_ctx != nullptr) {
3000 garciay 263
    ::BN_CTX_free(_bn_ctx);
2962 garciay 264
  }
3266 garciay 265
 
3115 garciay 266
  loggers::get_instance().log("<<< security_ecc::~security_ecc");
2962 garciay 267
} // End of Destructor
2955 garciay 268
 
3115 garciay 269
int security_ecc::generate() {
270
  loggers::get_instance().log(">>> security_ecc::generate");
2955 garciay 271
 
272
  // Sanity check
3100 garciay 273
  if (!::EC_KEY_generate_key(_ec_key)) { // Generate the private and public keys 
3115 garciay 274
    loggers::get_instance().error("security_ecc::generate: Failed to generate private/public keys");
2955 garciay 275
    return -1;
276
  }
277
 
3299 garciay 278
  BIGNUM* x = ::BN_new();
279
  BIGNUM* y = ::BN_new();
2955 garciay 280
  const EC_POINT* ec_point = EC_KEY_get0_public_key(_ec_key);
3189 garciay 281
  int result = 0;
282
  int size = 0;
283
  switch (_elliptic_curve) {
284
  case ec_elliptic_curves::nist_p_256: // Use primary
285
    // No break;
286
  case ec_elliptic_curves::brainpool_p_256_r1:
287
    size = 32;
3299 garciay 288
    result = ::EC_POINT_get_affine_coordinates_GFp(_ec_group, ec_point, x, y, _bn_ctx); // Use primer on elliptic curve
3189 garciay 289
    break;
290
  case ec_elliptic_curves::brainpool_p_384_r1:
291
    size = 48;
3299 garciay 292
    result = ::EC_POINT_get_affine_coordinates_GFp(_ec_group, ec_point, x, y, _bn_ctx); // Use primer on elliptic curve
3189 garciay 293
    break;
294
  default: // Use binary
3299 garciay 295
    result = ::EC_POINT_get_affine_coordinates_GF2m(_ec_group, ec_point, x, y, _bn_ctx);
3189 garciay 296
  } // End of 'switch' statement
297
  if (result == 0) {
298
    loggers::get_instance().error("security_ecc::generate: Failed to get coordinates");
299
  }
300
  const BIGNUM* p = ::EC_KEY_get0_private_key(_ec_key);
3185 garciay 301
 
3342 garciay 302
  _pri_key = int2oct(0, size);
303
  ::BN_bn2bin(p, (unsigned char*)static_cast<const unsigned char*>(_pri_key));
304
  _pub_key_x = int2oct(0, size);
305
  ::BN_bn2bin(x, (unsigned char*)static_cast<const unsigned char*>(_pub_key_x));
306
  _pub_key_y = int2oct(0, size);
307
  ::BN_bn2bin(y, (unsigned char*)static_cast<const unsigned char*>(_pub_key_y));
3299 garciay 308
  ::BN_clear_free(x); x = nullptr;
309
  ::BN_clear_free(y); y = nullptr;
2955 garciay 310
 
3100 garciay 311
  // Compressed
3342 garciay 312
  int len = ::EC_POINT_point2oct(_ec_group, ec_point, POINT_CONVERSION_COMPRESSED, nullptr, 0, _bn_ctx);
3177 garciay 313
  if (len == 0) {
314
    loggers::get_instance().warning("security_ecc::generate: Failed to generate x_coordinate compressed key");
315
  }
3342 garciay 316
  _pub_key_compressed = int2oct(0, len);
317
  if (::EC_POINT_point2oct(_ec_group, ec_point, POINT_CONVERSION_COMPRESSED, (unsigned char *)static_cast<const unsigned char*>(_pub_key_compressed), len, _bn_ctx) == 0) {
3177 garciay 318
    loggers::get_instance().warning("security_ecc::generate: Failed to generate x_coordinate compressed key");
3342 garciay 319
    _pub_key_compressed  = OCTETSTRING(0, nullptr);
3177 garciay 320
  } else { // Remove first byte
3342 garciay 321
    loggers::get_instance().log_msg("security_ecc::generate: Complete _pub_key_compressed=", _pub_key_compressed);
3343 garciay 322
    _pub_key_compressed_mode = ((_pub_key_compressed[0].get_octet() & 0x01) == 0x00) ? ecc_compressed_mode::compressed_y_0 : ecc_compressed_mode::compressed_y_1;
3342 garciay 323
    _pub_key_compressed = OCTETSTRING(_pub_key_compressed.lengthof() -1, 1 + static_cast<const unsigned char*>(_pub_key_compressed));
3177 garciay 324
  }
3342 garciay 325
  loggers::get_instance().log_msg("security_ecc::generate: _pri_key=", _pri_key);
326
  loggers::get_instance().log_msg("security_ecc::generate: _pub_key_x=", _pub_key_x);
327
  loggers::get_instance().log_msg("security_ecc::generate: _pub_key_y=", _pub_key_y);
328
  loggers::get_instance().log_msg("security_ecc::generate: _pub_key_compressed=", _pub_key_compressed);
3182 garciay 329
  loggers::get_instance().log("security_ecc::generate: _pub_key_compressed_mode=%d", _pub_key_compressed_mode);
2955 garciay 330
 
331
  return 0;
332
}
333
 
3342 garciay 334
int security_ecc::generate_and_derive_ephemeral_key(const encryption_algotithm p_enc_algorithm, const OCTETSTRING& p_recipients_public_key_x, const OCTETSTRING& p_recipients_public_key_y) {
3189 garciay 335
  loggers::get_instance().log(">>> security_ecc::generate_and_derive_ephemeral_key (1)");
3100 garciay 336
 
337
  // Sanity checks
3342 garciay 338
  if (_pri_key.lengthof() == 0) {
3189 garciay 339
    loggers::get_instance().warning("security_ecc::generate_and_derive_ephemeral_key (1): Key shall be generated");
3100 garciay 340
    return -1;
341
  }
3342 garciay 342
  if ((_pub_key_x.lengthof() == 0) || (_pub_key_y.lengthof() == 0)) {
3189 garciay 343
    loggers::get_instance().warning("security_ecc::generate_and_derive_ephemeral_key (1): Keys shall be generated");
3131 garciay 344
    return -1;
345
  }
346
  _encryption_algotithm = p_enc_algorithm;
3100 garciay 347
 
348
  // Set buffers size
349
  int len = (EC_GROUP_get_degree(_ec_group) + 7) / 8;
3342 garciay 350
  _secret_key = int2oct(0, len);
3137 garciay 351
  unsigned int nonce_length;
352
  unsigned int sym_key_length;
353
  unsigned int tag_length;
354
  switch (_encryption_algotithm) {
355
  case encryption_algotithm::aes_128_ccm:
356
    // No break;
357
  case encryption_algotithm::aes_128_gcm:
358
    nonce_length = 12;
359
    sym_key_length = 16;
360
    tag_length = 16;
3141 garciay 361
    break;
362
  default:
3189 garciay 363
    loggers::get_instance().warning("security_ecc::generate_and_derive_ephemeral_key (1): Unsupported encryption algorithm");
3141 garciay 364
    return -1;
365
  } // End of 'switch' statement
366
  unsigned int k_length;
367
  switch (_elliptic_curve) {
368
  case ec_elliptic_curves::nist_p_256: // Use the ANSI X9.62 Prime 256v1 curve 
369
    // No break;
370
  case ec_elliptic_curves::brainpool_p_256_r1:
3137 garciay 371
    k_length = 32;
372
    break;
3141 garciay 373
  case ec_elliptic_curves::brainpool_p_384_r1:
374
    k_length = 48;
375
    break;
3137 garciay 376
  default:
3189 garciay 377
    loggers::get_instance().warning("security_ecc::generate_and_derive_ephemeral_key (1): Unsupported encryption algorithm");
3137 garciay 378
    return -1;
379
  } // End of 'switch' statement
3132 garciay 380
 
3189 garciay 381
  // Convert the ephemeral public encryption keys to an EC point
3100 garciay 382
  EC_POINT *ec_point = nullptr;
3132 garciay 383
  bin_to_ec_point(p_recipients_public_key_x, p_recipients_public_key_y, &ec_point);
3116 garciay 384
  // Generate the shared secret key
3342 garciay 385
  int result = ::ECDH_compute_key((unsigned char*)static_cast<const unsigned char*>(_secret_key), _secret_key.lengthof(), ec_point, _ec_key, nullptr);
3100 garciay 386
  if (result == -1) {
3189 garciay 387
    loggers::get_instance().warning("security_ecc::generate_and_derive_ephemeral_key (1): Failed to generate shared secret key");
3100 garciay 388
    ::EC_POINT_free(ec_point);
389
    return -1;
390
  }
391
  ::EC_POINT_free(ec_point);
3342 garciay 392
  loggers::get_instance().log_msg("security_ecc::generate_and_derive_ephemeral_key (1): _secret_key: ", _secret_key);
3100 garciay 393
 
3131 garciay 394
  // Derive the shared secret key
3342 garciay 395
  const int k_enc = nonce_length + sym_key_length + tag_length;
396
  const int k_mac = k_length + k_length;
3344 garciay 397
  OCTETSTRING digest = int2oct(0, k_enc + k_mac);
3342 garciay 398
  loggers::get_instance().log("security_ecc::generate_and_derive_ephemeral_key (1): k_enc size:%d - k_mac size: %d - digest size:%d: ", k_enc, k_mac, digest.lengthof());
3343 garciay 399
  if (PKCS5_PBKDF2_HMAC((const char*)static_cast<const unsigned char*>(_secret_key), _secret_key.lengthof(), nullptr, 0, 2000, EVP_sha256(), digest.lengthof(), (unsigned char*)static_cast<const unsigned char*>(digest)) != 1) {
3136 garciay 400
    loggers::get_instance().warning("security_ecc::generate_and_derive_ephemeral_key: Failed to derive shared secret key");
3131 garciay 401
    return -1;
402
  }
3342 garciay 403
  loggers::get_instance().log_msg("security_ecc::generate_and_derive_ephemeral_key (1): digest: ", digest);
3131 garciay 404
 
405
  // Extract AES 128 parameters
3342 garciay 406
  _nonce = OCTETSTRING(nonce_length, static_cast<const unsigned char*>(digest));
407
  loggers::get_instance().log_msg("security_ecc::generate_and_derive_ephemeral_key (1): _nonce: ", _nonce);
408
  _sym_key = OCTETSTRING(sym_key_length, _nonce.lengthof() + static_cast<const unsigned char*>(digest));
409
  loggers::get_instance().log_msg("security_ecc::generate_and_derive_ephemeral_key (1): _sym_key: ", _sym_key);
410
  _tag = OCTETSTRING(tag_length, _nonce.lengthof() +  + _sym_key.lengthof() + static_cast<const unsigned char*>(digest)); // TODO Useless???
411
  loggers::get_instance().log_msg("security_ecc::generate_and_derive_ephemeral_key (1): _tag: ", _tag);
3131 garciay 412
  // Extract the HMAC key
3342 garciay 413
  OCTETSTRING hmac_secret = OCTETSTRING(k_length + k_length, nonce_length + sym_key_length + tag_length + static_cast<const unsigned char*>(digest));
414
  loggers::get_instance().log_msg("security_ecc::generate_and_derive_ephemeral_key (1): hmac_secret: ", hmac_secret);
3131 garciay 415
 
416
  // Encrypt the _sym_key
3132 garciay 417
  if (encrypt(encryption_algotithm::aes_128_ccm, _sym_key, _nonce, _sym_key, _enc_sym_key) == -1) {
3189 garciay 418
    loggers::get_instance().warning("security_ecc::generate_and_derive_ephemeral_key (1): Failed to encrypt key");
3131 garciay 419
    return -1;
420
  }
3342 garciay 421
  loggers::get_instance().log_msg("security_ecc::generate_and_derive_ephemeral_key (1): Encrypted symmetric key: ", encrypted_symmetric_key());
3131 garciay 422
 
3100 garciay 423
  return 0;
3101 garciay 424
}
3100 garciay 425
 
3342 garciay 426
int security_ecc::generate_and_derive_ephemeral_key(const encryption_algotithm p_enc_algorithm, const OCTETSTRING& p_private_enc_key, const OCTETSTRING& p_ephemeral_public_key_x, const OCTETSTRING& p_ephemeral_public_key_y, const OCTETSTRING& p_enc_sym_key, const OCTETSTRING& p_expected_nonce, const OCTETSTRING& p_authentication_vector) {
3189 garciay 427
  loggers::get_instance().log(">>> security_ecc::generate_and_derive_ephemeral_key (2)");
3136 garciay 428
 
429
  // Sanity checks
3342 garciay 430
  if (_pri_key.lengthof() == 0) {
3189 garciay 431
    loggers::get_instance().warning("security_ecc::generate_and_derive_ephemeral_key (2): Key shall be generated");
3136 garciay 432
    return -1;
433
  }
434
  _encryption_algotithm = p_enc_algorithm;
435
  _nonce = p_expected_nonce;
436
  _enc_sym_key = p_enc_sym_key;
437
  _tag = p_authentication_vector;
438
 
439
  // Set buffers size
440
  int len = (EC_GROUP_get_degree(_ec_group) + 7) / 8;
3342 garciay 441
  _secret_key = int2oct(0, len);
3137 garciay 442
  unsigned int nonce_length;
443
  unsigned int sym_key_length;
444
  unsigned int tag_length;
445
  switch (_encryption_algotithm) {
446
  case encryption_algotithm::aes_128_ccm:
447
    // No break;
448
  case encryption_algotithm::aes_128_gcm:
449
    nonce_length = 12;
450
    sym_key_length = 16;
451
    tag_length = 16;
3141 garciay 452
    break;
453
  default:
3189 garciay 454
    loggers::get_instance().warning("security_ecc::generate_and_derive_ephemeral_key (2): Unsupported encryption algorithm");
3141 garciay 455
    return -1;
456
  } // End of 'switch' statement
457
  unsigned int k_length;
458
  switch (_elliptic_curve) {
459
  case ec_elliptic_curves::nist_p_256: // Use the ANSI X9.62 Prime 256v1 curve 
460
    // No break;
461
  case ec_elliptic_curves::brainpool_p_256_r1:
3137 garciay 462
    k_length = 32;
463
    break;
3141 garciay 464
  case ec_elliptic_curves::brainpool_p_384_r1:
465
    k_length = 48;
466
    break;
3137 garciay 467
  default:
3189 garciay 468
    loggers::get_instance().warning("security_ecc::generate_and_derive_ephemeral_key (2): Unsupported encryption algorithm");
3137 garciay 469
    return -1;
470
  } // End of 'switch' statement
3136 garciay 471
 
472
  // Convert the peer public encryption key to an EC point
473
  EC_POINT *ec_point = nullptr;
474
  bin_to_ec_point(p_ephemeral_public_key_x, p_ephemeral_public_key_y, &ec_point);
475
  // Generate the shared symmetric key
3342 garciay 476
  int result = ::ECDH_compute_key((unsigned char*)static_cast<const unsigned char*>(_secret_key), _secret_key.lengthof(), ec_point, _ec_key, nullptr);
3136 garciay 477
  if (result == -1) {
478
    ::EC_POINT_free(ec_point);
479
    return -1;
480
  }
481
  ::EC_POINT_free(ec_point);
3342 garciay 482
  loggers::get_instance().log_msg("security_ecc::generate_and_derive_ephemeral_key (2): _secret_key: ", _secret_key);
3136 garciay 483
 
484
  // Derive the shared secret key
3342 garciay 485
  const int k_enc = nonce_length + sym_key_length + tag_length;
486
  const int k_mac = k_length + k_length;
3344 garciay 487
  OCTETSTRING digest = int2oct(0, k_enc + k_mac);
3342 garciay 488
  loggers::get_instance().log("security_ecc::generate_and_derive_ephemeral_key (2): k_enc size:%d - k_mac size: %d - digest size:%d: ", k_enc, k_mac, digest.lengthof());
3343 garciay 489
  if (PKCS5_PBKDF2_HMAC((const char*)static_cast<const unsigned char*>(_secret_key), _secret_key.lengthof(), nullptr, 0, 2000, EVP_sha256(), digest.lengthof(), (unsigned char*)static_cast<const unsigned char*>(digest)) != 1) {
3136 garciay 490
    loggers::get_instance().warning("security_ecc::generate_and_derive_ephemeral_key: Failed to derive shared secret key");
491
    return -1;
492
  }
3342 garciay 493
  loggers::get_instance().log_msg("security_ecc::generate_and_derive_ephemeral_key (2): digest: ", digest);
3136 garciay 494
 
495
  // Extract AES 128 parameters
3343 garciay 496
  OCTETSTRING nonce(nonce_length, static_cast<const unsigned char*>(digest));
497
  loggers::get_instance().log_msg("security_ecc::generate_and_derive_ephemeral_key (2): Generated nonce: ", nonce);
498
  OCTETSTRING sym_key(sym_key_length, nonce.lengthof() + static_cast<const unsigned char*>(digest));
499
  loggers::get_instance().log_msg("security_ecc::generate_and_derive_ephemeral_key (2): sym_key: ", sym_key);
3345 garciay 500
  OCTETSTRING tag(tag_length, nonce.lengthof() + sym_key.lengthof() + static_cast<const unsigned char*>(digest)); // TODO Useless???
3343 garciay 501
  loggers::get_instance().log_msg("security_ecc::generate_and_derive_ephemeral_key (2): tag: ", tag);
3141 garciay 502
  // Extract the HMAC key
3343 garciay 503
  OCTETSTRING hmac_secret(k_length + k_length, nonce_length + sym_key_length + tag_length + static_cast<const unsigned char*>(digest));
3342 garciay 504
  loggers::get_instance().log_msg("security_ecc::generate_and_derive_ephemeral_key (2): hmac_secret: ", hmac_secret);
3343 garciay 505
 
3141 garciay 506
  // Check if nonce vectors are valid
3136 garciay 507
  if (_nonce != nonce) {
3189 garciay 508
    loggers::get_instance().warning("security_ecc::generate_and_derive_ephemeral_key (2): Failed to derive nonce vector");
3136 garciay 509
    return -1;
510
  }
511
 
512
  // Decrypt the symmetric key
3342 garciay 513
  OCTETSTRING skey;
3136 garciay 514
  if (decrypt(p_enc_algorithm, sym_key, nonce, p_authentication_vector, p_enc_sym_key, skey) == -1) {
3189 garciay 515
    loggers::get_instance().warning("security_ecc::generate_and_derive_ephemeral_key (2): Failed to decrypt key");
3136 garciay 516
    return -1;
517
  }
518
  _sym_key = skey;
3342 garciay 519
  loggers::get_instance().log_msg("security_ecc::generate_and_derive_ephemeral_key (2): Decrypted symmetric key: ", symmetric_encryption_key());
3136 garciay 520
 
521
  return 0;
522
}
523
 
3342 garciay 524
int security_ecc::encrypt(const encryption_algotithm p_enc_algorithm, const OCTETSTRING& p_message, OCTETSTRING& p_enc_message) {
3115 garciay 525
  loggers::get_instance().log(">>> security_ecc::encrypt: %d", p_enc_algorithm);
3104 garciay 526
 
527
  // Sanity checks
3342 garciay 528
  if ((_pub_key_x.lengthof() != 0) || (_pub_key_y.lengthof() != 0)) {
3115 garciay 529
    loggers::get_instance().warning("security_ecc::encrypt: Constructor format #1 shall be used");
3104 garciay 530
    return -1;
531
  }
532
  _encryption_algotithm = p_enc_algorithm;
533
 
534
  // Initialize the context and encryption operation
535
  EVP_CIPHER_CTX *ctx = ::EVP_CIPHER_CTX_new();
536
  switch (_encryption_algotithm) {
537
  case encryption_algotithm::aes_128_ccm:
3342 garciay 538
    ::EVP_EncryptInit_ex(ctx, EVP_aes_128_ccm(), nullptr, nullptr, nullptr);
3104 garciay 539
    // Allocate buffers size
3342 garciay 540
    _nonce = int2oct(0, 12);
541
    _tag = int2oct(0, 16);
542
    _sym_key = int2oct(0, 16);
543
    p_enc_message = int2oct(0, p_message.lengthof());
3104 garciay 544
    break;
545
  case encryption_algotithm::aes_256_ccm:
3342 garciay 546
    ::EVP_EncryptInit_ex(ctx, EVP_aes_256_ccm(), nullptr, nullptr, nullptr);
3104 garciay 547
    break;
548
  case encryption_algotithm::aes_128_gcm:
3342 garciay 549
    ::EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), nullptr, nullptr, nullptr);
3104 garciay 550
    break;
551
  case encryption_algotithm::aes_256_gcm:
3342 garciay 552
    ::EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), nullptr, nullptr, nullptr);
3104 garciay 553
    break;
554
  } // End of 'switch' statement
3117 garciay 555
  // Generate _sym_key
3342 garciay 556
  ::RAND_bytes((unsigned char*)static_cast<const unsigned char*>(_sym_key), _sym_key.lengthof());
557
  loggers::get_instance().log_msg("security_ecc::encrypt: _sym_key: ", _sym_key);
3104 garciay 558
  // Generate _nonce
3342 garciay 559
  ::RAND_bytes((unsigned char*)static_cast<const unsigned char*>(_nonce), _nonce.lengthof());
560
  loggers::get_instance().log_msg("security_ecc::encrypt: nonce: ", _nonce);
3104 garciay 561
  // Set nonce length
3342 garciay 562
  ::EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, _nonce.lengthof(), nullptr);
3104 garciay 563
  // Set tag length
3342 garciay 564
  ::EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, _tag.lengthof(), nullptr);
3104 garciay 565
  // Prime the key and nonce
3342 garciay 566
  ::EVP_EncryptInit_ex(ctx, nullptr, nullptr, static_cast<const unsigned char*>(_sym_key), static_cast<const unsigned char*>(_nonce));
3104 garciay 567
  // No authentication data
568
  // Encrypt the data
569
  int len = 0;
3342 garciay 570
  ::EVP_EncryptUpdate(ctx, (unsigned char*)static_cast<const unsigned char*>(p_enc_message), &len, static_cast<const unsigned char*>(p_message), p_message.lengthof());
3104 garciay 571
  // Finalize the encryption session
3343 garciay 572
  ::EVP_EncryptFinal_ex(ctx, (unsigned char*)static_cast<const unsigned char*>(p_enc_message) + len, &len);
3342 garciay 573
  // Get the authentication tag(const char*)static_cast<const unsigned char*>(
574
  ::EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_GET_TAG, _tag.lengthof(), (unsigned char*)static_cast<const unsigned char*>(_tag));
575
  loggers::get_instance().log_msg("security_ecc::encrypt: tag: ", _tag);
3104 garciay 576
 
577
  ::EVP_CIPHER_CTX_free(ctx);
3117 garciay 578
 
579
  return 0;
580
}
581
 
3342 garciay 582
int security_ecc::encrypt(const encryption_algotithm p_enc_algorithm, const OCTETSTRING& p_symmetric_key, const OCTETSTRING& p_nonce, const OCTETSTRING& p_message, OCTETSTRING& p_enc_message) {
3117 garciay 583
  loggers::get_instance().log(">>> security_ecc::encrypt (2): %d", p_enc_algorithm);
584
 
585
  _encryption_algotithm = p_enc_algorithm;
586
  _sym_key = p_symmetric_key;
587
  _nonce = p_nonce;
588
 
589
  // Initialize the context and encryption operation
590
  EVP_CIPHER_CTX *ctx = ::EVP_CIPHER_CTX_new();
591
  switch (_encryption_algotithm) {
592
  case encryption_algotithm::aes_128_ccm:
3342 garciay 593
    ::EVP_EncryptInit_ex(ctx, EVP_aes_128_ccm(), nullptr, nullptr, nullptr);
3117 garciay 594
    // Allocate buffers size
3342 garciay 595
    _tag = int2oct(0, 16);
3343 garciay 596
    p_enc_message = int2oct(0, p_message.lengthof());
3117 garciay 597
    break;
598
  case encryption_algotithm::aes_256_ccm:
3342 garciay 599
    ::EVP_EncryptInit_ex(ctx, EVP_aes_256_ccm(), nullptr, nullptr, nullptr);
3117 garciay 600
    break;
601
  case encryption_algotithm::aes_128_gcm:
3342 garciay 602
    ::EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), nullptr, nullptr, nullptr);
3117 garciay 603
    break;
604
  case encryption_algotithm::aes_256_gcm:
3342 garciay 605
    ::EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), nullptr, nullptr, nullptr);
3117 garciay 606
    break;
607
  } // End of 'switch' statement
3342 garciay 608
  loggers::get_instance().log_msg("security_ecc::encrypt: _sym_key: ", _sym_key);
609
  loggers::get_instance().log_msg("security_ecc::encrypt: nonce: ", _nonce);
3117 garciay 610
  // Set nonce length
3342 garciay 611
  ::EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, _nonce.lengthof(), nullptr);
3117 garciay 612
  // Set tag length
3342 garciay 613
  ::EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, _tag.lengthof(), nullptr);
3117 garciay 614
  // Prime the key and nonce
3343 garciay 615
  ::EVP_EncryptInit_ex(ctx, nullptr, nullptr, static_cast<const unsigned char*>(_sym_key), static_cast<const unsigned char*>(_nonce));
3117 garciay 616
  // No authentication data
617
  // Encrypt the data
618
  int len = 0;
3342 garciay 619
  ::EVP_EncryptUpdate(ctx, (unsigned char*)static_cast<const unsigned char*>(p_enc_message), &len, static_cast<const unsigned char*>(p_message), p_message.lengthof());
3117 garciay 620
  // Finalize the encryption session
3342 garciay 621
  ::EVP_EncryptFinal_ex(ctx, (unsigned char*)static_cast<const unsigned char*>(p_enc_message) + len, &len);
3117 garciay 622
  // Get the authentication tag
3342 garciay 623
  ::EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_GET_TAG, _tag.lengthof(), (unsigned char*)static_cast<const unsigned char*>(_tag));
624
  loggers::get_instance().log_msg("security_ecc::encrypt: tag: ", _tag);
3117 garciay 625
 
626
  ::EVP_CIPHER_CTX_free(ctx);
3104 garciay 627
 
628
  return 0;
629
}
630
 
3342 garciay 631
int security_ecc::decrypt(const encryption_algotithm p_enc_algorithm, const OCTETSTRING& p_key, const OCTETSTRING& p_nonce, const OCTETSTRING& p_tag, const OCTETSTRING& p_enc_message, OCTETSTRING& p_message) {
3136 garciay 632
  loggers::get_instance().log(">>> security_ecc::decrypt: %d", p_enc_algorithm);
3104 garciay 633
 
634
  _encryption_algotithm = p_enc_algorithm;
3117 garciay 635
  _sym_key = p_key;
3104 garciay 636
  _nonce = p_nonce;
637
  _tag = p_tag;
638
 
639
  // Initialize the context and decryption operation
640
  EVP_CIPHER_CTX *ctx = ::EVP_CIPHER_CTX_new();
641
  switch (_encryption_algotithm) {
642
  case encryption_algotithm::aes_128_ccm:
3342 garciay 643
    ::EVP_DecryptInit_ex(ctx, EVP_aes_128_ccm(), nullptr, nullptr, nullptr);
3104 garciay 644
    break;
645
  case encryption_algotithm::aes_256_ccm:
3342 garciay 646
    ::EVP_DecryptInit_ex(ctx, EVP_aes_256_ccm(), nullptr, nullptr, nullptr);
3104 garciay 647
    break;
648
  case encryption_algotithm::aes_128_gcm:
3342 garciay 649
    ::EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), nullptr, nullptr, nullptr);
3104 garciay 650
    break;
651
  case encryption_algotithm::aes_256_gcm:
3342 garciay 652
    ::EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), nullptr, nullptr, nullptr);
3104 garciay 653
    break;
654
  } // End of 'switch' statement
655
  // Set nonce length
3342 garciay 656
  EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, _nonce.lengthof(), nullptr);
3104 garciay 657
  // Set expected tag value
3343 garciay 658
  EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, _tag.lengthof(), (unsigned char*)static_cast<const unsigned char*>(_tag));
3104 garciay 659
  // Specify key and IV
3342 garciay 660
  EVP_DecryptInit_ex(ctx, nullptr, nullptr, static_cast<const unsigned char*>(_sym_key), static_cast<const unsigned char*>(_nonce));
3104 garciay 661
  // Decrypt plaintext, verify tag: can only be called once
3343 garciay 662
  p_message = int2oct(0, p_enc_message.lengthof());
3104 garciay 663
  int len = 0;
3342 garciay 664
  int result = EVP_DecryptUpdate(ctx, (unsigned char*)static_cast<const unsigned char*>(p_message), &len, static_cast<const unsigned char*>(p_enc_message), p_enc_message.lengthof());
3136 garciay 665
  loggers::get_instance().log("security_ecc::decrypt: len: %d", len);
666
  loggers::get_instance().log("security_ecc::decrypt: result: %d", result);
3104 garciay 667
  ::EVP_CIPHER_CTX_free(ctx);
668
 
669
  return (result > 0) ? 0 : -1;
670
}
3116 garciay 671
 
3342 garciay 672
int security_ecc::decrypt(const OCTETSTRING& p_tag, const OCTETSTRING& p_enc_message, OCTETSTRING& p_message) {
3136 garciay 673
  loggers::get_instance().log(">>> security_ecc::decrypt: %d", _encryption_algotithm);
3100 garciay 674
 
675
  // Sanity checks
3342 garciay 676
  if ((_pri_key.lengthof() == 0) || (_secret_key.lengthof() == 0)) {
3115 garciay 677
    loggers::get_instance().warning("security_ecc::decrypt: Constrictor format #2 shall be used");
3100 garciay 678
    return -1;
679
  }
680
  _tag = p_tag;
681
 
682
  // Initialize the context and decryption operation
683
  EVP_CIPHER_CTX *ctx = ::EVP_CIPHER_CTX_new();
684
  switch (_encryption_algotithm) {
685
  case encryption_algotithm::aes_128_ccm:
3342 garciay 686
    ::EVP_DecryptInit_ex(ctx, EVP_aes_128_ccm(), nullptr, nullptr, nullptr);
3100 garciay 687
    break;
688
  case encryption_algotithm::aes_256_ccm:
3342 garciay 689
    ::EVP_DecryptInit_ex(ctx, EVP_aes_256_ccm(), nullptr, nullptr, nullptr);
3100 garciay 690
    break;
691
  case encryption_algotithm::aes_128_gcm:
3342 garciay 692
    ::EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), nullptr, nullptr, nullptr);
3100 garciay 693
    break;
694
  case encryption_algotithm::aes_256_gcm:
3342 garciay 695
    ::EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), nullptr, nullptr, nullptr);
3100 garciay 696
    break;
697
  } // End of 'switch' statement
698
  // Set nonce length
3342 garciay 699
  EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, _nonce.lengthof(), nullptr);
3100 garciay 700
  // Set expected tag value
3343 garciay 701
  EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, _tag.lengthof(), (unsigned char*)static_cast<const unsigned char*>(_tag));
3100 garciay 702
  // Specify key and IV
3342 garciay 703
  EVP_DecryptInit_ex(ctx, nullptr, nullptr, static_cast<const unsigned char*>(_sym_key), static_cast<const unsigned char*>(_nonce));
3100 garciay 704
  // Decrypt plaintext, verify tag: can only be called once
3343 garciay 705
  p_message = int2oct(0, p_enc_message.lengthof());
3101 garciay 706
  int len = 0;
3342 garciay 707
  int result = EVP_DecryptUpdate(ctx, (unsigned char*)static_cast<const unsigned char*>(p_message), &len, static_cast<const unsigned char*>(p_enc_message), p_enc_message.lengthof());
3136 garciay 708
  loggers::get_instance().log("security_ecc::decrypt: len: %d", len);
709
  loggers::get_instance().log("security_ecc::decrypt: result: %d", result);
3100 garciay 710
  ::EVP_CIPHER_CTX_free(ctx);
711
 
712
  return (result > 0) ? 0 : -1;
713
}
714
 
3342 garciay 715
int security_ecc::sign(const OCTETSTRING& p_data, OCTETSTRING& p_r_sig, OCTETSTRING& p_s_sig) {
3115 garciay 716
  loggers::get_instance().log(">>> security_ecc::sign");
3342 garciay 717
  loggers::get_instance().log_msg(">>> security_ecc::sign: p_data: ", p_data);
2955 garciay 718
 
719
  // Sanity checks
3342 garciay 720
  if(_pri_key.lengthof() == 0) { // No private key
2955 garciay 721
    return -1;
722
  }
3342 garciay 723
  if (p_data.lengthof() == 0) {
2967 garciay 724
    return -1;
725
  }
2955 garciay 726
 
3342 garciay 727
  ECDSA_SIG *signature = ::ECDSA_do_sign(static_cast<const unsigned char*>(p_data), p_data.lengthof(), _ec_key);
2955 garciay 728
  if (signature == nullptr) {
3115 garciay 729
    loggers::get_instance().warning("security_ecc::sign: Signature failed");
2955 garciay 730
    return -1;
731
  }
3115 garciay 732
  loggers::get_instance().log("security_ecc::sign: succeed");
2955 garciay 733
 
3342 garciay 734
  if (::ECDSA_do_verify(static_cast<const unsigned char*>(p_data), p_data.lengthof(), signature, _ec_key) != 1) {
3115 garciay 735
    loggers::get_instance().warning("security_ecc::sign: Signature not verified");
2955 garciay 736
    return -1;
737
  }
3299 garciay 738
 
739
  const BIGNUM* r = nullptr;
740
  const BIGNUM* s = nullptr;
741
  ::ECDSA_SIG_get0(signature, &r, &s);
3350 garciay 742
  loggers::get_instance().log("security_ecc::sign: r size: %d", BN_num_bytes(r));
3342 garciay 743
  p_r_sig = int2oct(0, BN_num_bytes(r));
744
  ::BN_bn2bin(r, (unsigned char*)static_cast<const unsigned char*>(p_r_sig));
745
  loggers::get_instance().log_msg("security_ecc::sign: r=", p_r_sig);
3350 garciay 746
  loggers::get_instance().log("security_ecc::sign: s size: %d", BN_num_bytes(s));
3342 garciay 747
  p_s_sig = int2oct(0, BN_num_bytes(s));
748
  ::BN_bn2bin(s, (unsigned char*)static_cast<const unsigned char*>(p_s_sig));
749
  loggers::get_instance().log_msg("security_ecc::sign: s=", p_s_sig);
2955 garciay 750
 
751
  ::ECDSA_SIG_free(signature);
752
 
753
  return 0;
754
}
755
 
3342 garciay 756
int security_ecc::sign_verif(const OCTETSTRING& p_data, const OCTETSTRING& p_signature) {
3115 garciay 757
  loggers::get_instance().log(">>> security_ecc::sign_verif");
3342 garciay 758
  loggers::get_instance().log_msg(">>> security_ecc::sign_verify: p_data: ", p_data);
2955 garciay 759
 
760
  // Sanity checks
3342 garciay 761
  if (p_data.lengthof() == 0) {
3270 garciay 762
    return -1;
2967 garciay 763
  }
2955 garciay 764
 
765
  // Build the signature
3342 garciay 766
  BIGNUM* r = ::BN_bin2bn(static_cast<const unsigned char*>(p_signature), p_signature.lengthof() / 2, nullptr);
767
  loggers::get_instance().log_to_hexa("security_ecc::sign_verify: r=", static_cast<const unsigned char*>(p_signature), p_signature.lengthof() / 2);
768
  BIGNUM* s = ::BN_bin2bn(static_cast<const unsigned char*>(p_signature) + p_signature.lengthof() / 2, p_signature.lengthof() / 2, nullptr);
769
  loggers::get_instance().log_to_hexa("security_ecc::sign_verify: s=", static_cast<const unsigned char*>(p_signature) + p_signature.lengthof() / 2, p_signature.lengthof() / 2);
2955 garciay 770
  ECDSA_SIG *signature = ECDSA_SIG_new();
3299 garciay 771
  ::ECDSA_SIG_set0(signature, r, s);
2967 garciay 772
  // Check the signature
3342 garciay 773
  int result = ::ECDSA_do_verify(static_cast<const unsigned char*>(p_data), p_data.lengthof(), signature, _ec_key);
2955 garciay 774
  ::ECDSA_SIG_free(signature);
3115 garciay 775
  loggers::get_instance().log("security_ecc::sign_verif: %s", (result == 1) ? "succeed": "failed");
3270 garciay 776
  return (result == 1) ? 0 : -1;
2955 garciay 777
}
3115 garciay 778
const int security_ecc::init() {
779
  loggers::get_instance().log(">>> security_ecc::init: %d", static_cast<int>(_elliptic_curve));
3000 garciay 780
 
781
  ::OpenSSL_add_all_algorithms();
2961 garciay 782
  ::ERR_load_crypto_strings();
3266 garciay 783
  ::ERR_clear_error();
2961 garciay 784
 
2967 garciay 785
  int result = -1;
3137 garciay 786
  switch (_elliptic_curve) {
2961 garciay 787
  case ec_elliptic_curves::nist_p_256: // Use the ANSI X9.62 Prime 256v1 curve 
788
    result = ::OBJ_txt2nid("prime256v1");
789
    break;
790
  case ec_elliptic_curves::brainpool_p_256_r1:
791
    result = ::OBJ_txt2nid("brainpoolP256r1");
792
    break;
793
  case ec_elliptic_curves::brainpool_p_384_r1:
794
    result = ::OBJ_txt2nid("brainpoolP384r1");
795
    break;
796
  default:
3141 garciay 797
    loggers::get_instance().error("security_ecc::init: Unsupported EC elliptic_curve");
2961 garciay 798
  } // End of 'switch' statement
3000 garciay 799
  if (result < 0) {
3141 garciay 800
    loggers::get_instance().warning("security_ecc::init: Unaible to set EC elliptic_curve");
3000 garciay 801
    return -1;
802
  }
3223 garciay 803
  loggers::get_instance().log("security_ecc::init: Nid=%d", result);
3000 garciay 804
 
805
  _ec_key = ::EC_KEY_new_by_curve_name(result); // Set the elliptic curve
2961 garciay 806
  ::EC_KEY_set_asn1_flag(_ec_key, OPENSSL_EC_NAMED_CURVE); // Used to save and retrieve keys
807
  _ec_group = ::EC_KEY_get0_group(_ec_key); // Get pointer to the EC_GROUP
808
  _bn_ctx = ::BN_CTX_new();
809
 
810
  return 0;
811
} // End of init
812
 
3342 garciay 813
int security_ecc::bin_to_ec_point(const OCTETSTRING& p_public_key_x, const OCTETSTRING& p_public_key_y, EC_POINT** p_ec_point) { // ec_key_public_key_bin_to_point
3100 garciay 814
  BIGNUM* pubk_bn;
815
 
3343 garciay 816
  OCTETSTRING v = int2oct(4, 1);
3342 garciay 817
  v += p_public_key_x;
818
  v += p_public_key_y;
3100 garciay 819
 
3342 garciay 820
  pubk_bn = ::BN_bin2bn(static_cast<const unsigned char*>(v), v.lengthof(), nullptr);
3100 garciay 821
  *p_ec_point = ::EC_POINT_new(_ec_group);
822
  ::EC_POINT_bn2point(_ec_group, pubk_bn, *p_ec_point, _bn_ctx);
3345 garciay 823
  ::BN_clear_free(pubk_bn);
3266 garciay 824
 
3342 garciay 825
  // BIO            *bio_out  = nullptr; /* stdout */
3100 garciay 826
  // bio_out = BIO_new_fp(stdout, BIO_NOCLOSE);
827
  // BIGNUM *x = BN_new();
828
  // BIGNUM *y = BN_new();
829
 
3342 garciay 830
  // if (EC_POINT_get_affine_coordinates_GFp(_ec_group, *p_ec_point, x, y, nullptr)) {
3100 garciay 831
  //   BN_print_fp(stdout, x);
832
  //   putc('\n', stdout);
833
  //   BN_print_fp(stdout, y);
834
  //   putc('\n', stdout);
835
  // }
836
  // BN_free(x); BN_free(y);
837
 
838
  return 0;
839
}
840
 
3342 garciay 841
int security_ecc::public_key_to_bin(OCTETSTRING& p_bin_key) { // ec_key_public_key_to_bin
3100 garciay 842
  const EC_GROUP *ec_group   = EC_KEY_get0_group(_ec_key);
843
  const EC_POINT *pub        = EC_KEY_get0_public_key(_ec_key);
844
  BIGNUM         *pub_bn     = BN_new();
845
 
846
  ::EC_POINT_point2bn(ec_group, pub, POINT_CONVERSION_UNCOMPRESSED, pub_bn, _bn_ctx);
3342 garciay 847
  p_bin_key = int2oct(0, BN_num_bytes(pub_bn));
848
  ::BN_bn2bin(pub_bn, (unsigned char*)static_cast<const unsigned char*>(p_bin_key));
3100 garciay 849
 
850
  ::BN_clear_free(pub_bn);
851
 
852
  return 0;
3131 garciay 853
}