首页
社区
课程
招聘
[原创]C++ECIES随便一甩。
发表于: 2017-9-14 01:07 4783

[原创]C++ECIES随便一甩。

2017-9-14 01:07
4783
/**
* Author:    DengTao
* Created:   2017.08.07
*
* (c) Copyright by DengTao.
**/
#include "ecies/bignum_key.h"

#include <openssl/err.h>
#include <openssl/ec.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/rand.h>
#include <openssl/bio.h>
#include <openssl/bn.h>
#include <openssl/hmac.h>

namespace FinSky{
  EC_POINT *EC_POINT_mult_BN(const EC_GROUP *group, EC_POINT *P, const EC_POINT *a, const BIGNUM *b, BN_CTX *ctx) {
    EC_POINT *O = EC_POINT_new(group);
    if (P == NULL) P = EC_POINT_new(group);
    for (int i = BN_num_bits(b); i >= 0; i--) {
      EC_POINT_dbl(group, P, P, ctx);
      if (BN_is_bit_set(b, i))
        EC_POINT_add(group, P, P, a, ctx);
      else
        EC_POINT_add(group, P, P, O, ctx);
    }
    return P;
  }
  BigNumKey::BigNumKey() :
    public_handle_s_(0),
    public_handle_r_(0),
    private_handle_s_(0),
    private_handle_r_(0),
    ec_key_handle_(0){
    public_s_.resize(0);
    public_r_.resize(0);
    private_s_.resize(0);
    private_r_.resize(0);
  }
  BigNumKey::~BigNumKey(){
    public_s_.resize(0);
    public_r_.resize(0);
    private_s_.resize(0);
    private_r_.resize(0);
    BN_free(reinterpret_cast<BIGNUM*>(public_handle_r_.get()));
    BN_free(reinterpret_cast<BIGNUM*>(public_handle_s_.get()));
    BN_free(reinterpret_cast<BIGNUM*>(private_handle_r_.get()));
    BN_free(reinterpret_cast<BIGNUM*>(private_handle_s_.get()));
  }
  bool BigNumKey::SetECKey(const std::string& private_key){
    BIO *b = BIO_new_mem_buf((void*)private_key.c_str(), private_key.size());
    EVP_PKEY *pkey = NULL;
    if (private_key.find("PRIVATE") != std::string::npos)
      PEM_read_bio_PrivateKey(b, &pkey, NULL, NULL);
    else
      PEM_read_bio_PUBKEY(b, &pkey, NULL, NULL);
    ec_key_handle_ = (BigNumKeyHandle)EVP_PKEY_get1_EC_KEY(pkey);
    BIO_free(b);
    EVP_PKEY_free(pkey);
    return true;
  }
  bool BigNumKey::ECKeyPublicDeriveRS(){
    //////////////////////////////////////////////////////////////////////////
    public_handle_r_ = (BigNumKeyHandle)BN_new();
    public_handle_s_ = (BigNumKeyHandle)BN_new();
    BN_CTX *ctx = BN_CTX_new();
    const EC_GROUP *group = EC_KEY_get0_group(reinterpret_cast<EC_KEY*>(ec_key_handle_.get()));
    const EC_POINT *Kb = EC_KEY_get0_public_key(reinterpret_cast<EC_KEY*>(ec_key_handle_.get()));
    BIGNUM *n = BN_new();
    BIGNUM *r = BN_new();
    EC_POINT *P = NULL;
    EC_POINT *Rp = EC_POINT_new(group);
    BIGNUM *Py = BN_new();
    const EC_POINT *G = EC_GROUP_get0_generator(group);
    int bits, ret = -1;
    EC_GROUP_get_order(group, n, ctx);
    bits = BN_num_bits(n);
    BN_rand(r, bits, -1, 0);
    /* calculate R = rG */
    Rp = EC_POINT_mult_BN(group, Rp, G, r, ctx);
    /* calculate S = Px, P = (Px,Py) = Kb R */
    P = EC_POINT_mult_BN(group, P, Kb, r, ctx);
    if (!EC_POINT_is_at_infinity(group, P)) {
      EC_POINT_get_affine_coordinates_GF2m(group, P, reinterpret_cast<BIGNUM*>(public_handle_s_.get()), Py, ctx);
      EC_POINT_point2bn(group, Rp, POINT_CONVERSION_COMPRESSED, reinterpret_cast<BIGNUM*>(public_handle_r_.get()), ctx);
      ret = 0;
    }
    BN_free(r);
    BN_free(n);
    BN_free(Py);
    EC_POINT_free(P);
    EC_POINT_free(Rp);
    BN_CTX_free(ctx);
    return (ret!=0);
  }
  bool BigNumKey::ECKeyPrivateDeriveRS(){
    //ReversePublicR();
    private_handle_r_ = (BigNumKeyHandle)BN_bin2bn(&public_r_[0], public_r_.size(), BN_new());
    private_handle_s_ = (BigNumKeyHandle)BN_new();
    int ret = -1;
    BN_CTX *ctx = BN_CTX_new();
    BIGNUM *n = BN_new();
    BIGNUM *Py = BN_new();
    const EC_GROUP *group = EC_KEY_get0_group(reinterpret_cast<EC_KEY*>(ec_key_handle_.get()));
    EC_POINT *Rp = EC_POINT_bn2point(group, reinterpret_cast<BIGNUM*>(private_handle_r_.get()), NULL, ctx);
    const BIGNUM *kB = EC_KEY_get0_private_key(reinterpret_cast<EC_KEY*>(ec_key_handle_.get()));
    EC_GROUP_get_order(group, n, ctx);
    /* Calculate S = Px, P = (Px, Py) = R kB */
    EC_POINT *P = EC_POINT_mult_BN(group, NULL, Rp, kB, ctx);
    if (!EC_POINT_is_at_infinity(group, P)) {
      EC_POINT_get_affine_coordinates_GF2m(group, P, reinterpret_cast<BIGNUM*>(private_handle_s_.get()), Py, ctx);
      ret = 0;
    }
    BN_free(n);
    BN_free(Py);
    EC_POINT_free(Rp);
    EC_POINT_free(P);
    BN_CTX_free(ctx);
    return (ret!=0);
  }
  void BigNumKey::PublicR(){
    public_r_.resize(BN_num_bytes(reinterpret_cast<BIGNUM*>(public_handle_r_.get())));
    BN_bn2bin(reinterpret_cast<const BIGNUM*>(public_handle_r_.get()), &public_r_[0]);
  }
  void BigNumKey::PublicS(){
    public_s_.resize(BN_num_bytes(reinterpret_cast<BIGNUM*>(public_handle_s_.get())));
    BN_bn2bin(reinterpret_cast<const BIGNUM*>(public_handle_s_.get()), &public_s_[0]);
  }
  void BigNumKey::PrivateR(){
    private_r_.resize(BN_num_bytes(reinterpret_cast<BIGNUM*>(private_handle_r_.get())));
    BN_bn2bin(reinterpret_cast<BIGNUM*>(private_handle_r_.get()), &private_r_[0]);
  }
  void BigNumKey::PrivateS(){
    private_s_.resize(BN_num_bytes(reinterpret_cast<BIGNUM*>(private_handle_s_.get())));
    BN_bn2bin(reinterpret_cast<BIGNUM*>(private_handle_s_.get()), &private_s_[0]);
  }
  void BigNumKey::ReversePublicR(){
    public_r_.resize(BN_num_bytes(reinterpret_cast<BIGNUM*>(public_handle_r_.get())));
    BN_bn2bin(reinterpret_cast<BIGNUM*>(public_handle_r_.get()), &public_r_[0]);
  }
}
/**
* Author:    DengTao
* Created:   2017.08.07
*
* (c) Copyright by DengTao.
**/
#include "ecies/decrypt_message.h"

#include <openssl/err.h>
#include <openssl/ec.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/rand.h>
#include <openssl/bio.h>
#include <openssl/bn.h>
#include <openssl/hmac.h>

namespace FinSky{
  DecryptMessage::DecryptMessage(const std::string& private_key){
    key_.SetECKey(private_key);
    salt_.resize(0);
    checksum_.resize(0);
  }
  DecryptMessage::~DecryptMessage(){
    salt_.resize(0);
    checksum_.resize(0);
  }
  bool DecryptMessage::DecryptBytes(const std::vector<std::uint8_t>& bytes){
    key_.ECKeyPrivateDeriveRS();
    key_.PrivateS();
    std::vector<std::uint8_t> private_s = key_.private_s();
    const EVP_MD *md = EVP_sha1();
    const EVP_CIPHER *cipher = EVP_aes_256_cbc();
    size_t ke_len = EVP_CIPHER_key_length(cipher) + EVP_CIPHER_iv_length(cipher);
    size_t km_len = EVP_MD_block_size(md);
    unsigned char *ke_km = new unsigned char[ke_len + km_len];
    memset(ke_km, 0, ke_len + km_len);
    unsigned char *dc_out = new unsigned char[bytes.size() * 5];
    assert(ke_km != nullptr&&dc_out != nullptr);
    memset(dc_out, 0, bytes.size() * 5);
    size_t dc_len = 0;
    int outl = 0;

    PKCS5_PBKDF2_HMAC((const char*)&private_s[0], private_s.size(), &salt_[0], salt_.size(), kHMACIter, md, ke_len + km_len, ke_km);

    unsigned char *dv_out = new unsigned char[km_len];
    assert(dv_out != nullptr);
    unsigned int dv_len;
    HMAC(md, ke_km + ke_len, km_len, &bytes[0], bytes.size(), dv_out, &dv_len);

    if (checksum_.size() != dv_len || memcmp(dv_out, &checksum_[0], dv_len) != 0){
      printf("MAC verification failed\n");
      return true;
    }

    EVP_CIPHER_CTX *ectx = EVP_CIPHER_CTX_new();

    EVP_DecryptInit_ex(ectx, cipher, NULL, ke_km, ke_km + EVP_CIPHER_key_length(cipher));
    EVP_DecryptUpdate(ectx, dc_out + dc_len, &outl, &bytes[0], bytes.size());
    dc_len += outl;
    EVP_DecryptFinal_ex(ectx, dc_out + dc_len, &outl);
    dc_len += outl;
    dc_out[dc_len] = 0;
    clear_text_.resize(dc_len);
    memmove(&clear_text_[0], dc_out, dc_len);
    delete[] dc_out;
    delete[] ke_km;
    delete[] dv_out;
    return 0;
  }
  void DecryptMessage::SetPublicR(const std::vector<std::uint8_t>& s3){
    key_.SetPublicR(s3);
  }
}
/**
* Author:    DengTao
* Created:   2017.08.07
*
* (c) Copyright by DengTao.
**/
#include "ecies/encrypt_message.h"

#include <openssl/err.h>
#include <openssl/ec.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/rand.h>
#include <openssl/bio.h>
#include <openssl/bn.h>
#include <openssl/hmac.h>

namespace FinSky{
  EncryptMessage::EncryptMessage(const std::string& private_key){
    key_.SetECKey(private_key);
    salt_.resize(32);
    checksum_.resize(0);
    cipher_text_.resize(0);
    RAND_bytes(&salt_[0], salt_.size());
  }
  EncryptMessage::~EncryptMessage(){
    salt_.resize(0);
    checksum_.resize(0);
    cipher_text_.resize(0);
  }
  bool EncryptMessage::EncryptString(const std::string& str){
    std::vector<std::uint8_t> v;
    std::copy(str.begin(), str.end(), std::back_inserter(v));
    return EncryptBytes(v);
  }
  bool EncryptMessage::EncryptBytes(const std::vector<std::uint8_t>& bytes){
    unsigned char *c_out = new unsigned char[bytes.size() * 5]; size_t c_len;
    unsigned char *d_out = new unsigned char[bytes.size() * 5]; size_t d_len;
    assert(c_out != nullptr&&d_out != nullptr);
    memset(c_out, 0, bytes.size() * 5);
    memset(d_out, 0, bytes.size() * 5);
    const std::vector<std::uint8_t> loc_salt = salt();
    key_.ECKeyPublicDeriveRS();
    key_.PublicS();
    std::vector<std::uint8_t> public_s = key_.public_s();
    const EVP_MD *md = EVP_sha1();
    const EVP_CIPHER *cipher = EVP_aes_256_cbc();
    size_t ke_len = EVP_CIPHER_key_length(cipher) + EVP_CIPHER_iv_length(cipher);
    size_t km_len = EVP_MD_block_size(md);
    unsigned char *ke_km = new unsigned char[ke_len + km_len];
    assert(ke_km != nullptr);
    memset(ke_km, 0, ke_len + km_len);
    c_len = 0;
    int outl = 0;
    PKCS5_PBKDF2_HMAC((const char*)(const char*)&public_s[0], public_s.size(), &loc_salt[0], loc_salt.size(), kHMACIter, md, ke_len + km_len, ke_km);
    EVP_CIPHER_CTX *ectx = EVP_CIPHER_CTX_new();
    EVP_EncryptInit_ex(ectx, cipher, NULL, ke_km, ke_km + EVP_CIPHER_key_length(cipher));
    EVP_EncryptUpdate(ectx, c_out + c_len, &outl, (const unsigned char*)&bytes[0], bytes.size());
    c_len += outl;
    EVP_EncryptFinal_ex(ectx, c_out + c_len, &outl);
    c_len += outl;
    unsigned int len;
    HMAC(md, ke_km + ke_len, km_len, c_out, c_len, d_out, &len);
    d_len = len;
    checksum_.resize(d_len);
    cipher_text_.resize(c_len);
    memmove(&cipher_text_[0], c_out, c_len);
    memmove(&checksum_[0], d_out, d_len);
    key_.ReversePublicR();
    public_r_ = key_.public_r();
    delete[] c_out;
    delete[] d_out;
    delete[] ke_km;
    return false;
  }
}
// openssl_ecies.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#define _CRTDBG_MAP_ALLOC
#include<stdlib.h>
#include<crtdbg.h>
#pragma comment(lib,"libcrypto.lib")
#pragma comment(lib,"libssl.lib")
#include <openssl/err.h>
#include <openssl/ec.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/rand.h>
#include <openssl/bio.h>
#include <openssl/bn.h>
#include <openssl/hmac.h>
#include "BigNumKey.h"
#include "EncryptMessage.h"
#include "DecryptMessage.h"

const char pkey[] = "-----BEGIN PUBLIC KEY-----\n" \
"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEgv/5+wE/2gT5ANCpZ9kIy3nKgcqH\n" \
"YDyNC/d0bgf9Pdaus40CXjIZukF1uUAWAo4GTqG7uDatXWOzq1MIDgE6bA==\n" \
"-----END PUBLIC KEY-----\n";
const char privkey[] = "-----BEGIN EC PRIVATE KEY-----\n" \
"MHcCAQEEILmUAvLj7GGSykQxpHeems8Yjw03V7ACBmD8udiNm92soAoGCCqGSM49\n" \
"AwEHoUQDQgAEgv/5+wE/2gT5ANCpZ9kIy3nKgcqHYDyNC/d0bgf9Pdaus40CXjIZ\n" \
"ukF1uUAWAo4GTqG7uDatXWOzq1MIDgE6bA==\n" \
"-----END EC PRIVATE KEY-----\n";

int _tmain(int argc, _TCHAR* argv[])
{
  _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
  //https://github.com/cmouse/ecies/blob/master/ecies.c
  //openssl ecparam -genkey -name prime256v1 -noout -out ecprivkey.pem
  //openssl ec -in ecprivkey.pem -pubout -out ecpubkey.pem
  OpenSSL_add_all_algorithms();
  ERR_load_crypto_strings();
  const std::string msg = "super secret message";
  const std::string public_key = pkey;
  ECIES::EncryptMessage encrypt_message(public_key);
  encrypt_message.EncryptString(msg);
  std::vector<std::uint8_t> salt = encrypt_message.salt();
  std::vector<std::uint8_t> checksum = encrypt_message.checksum();
  std::vector<std::uint8_t> ciphertext = encrypt_message.cipher_text();

  const std::string private_key = privkey;
  ECIES::DecryptMessage decrypt_message(private_key);
  decrypt_message.SetSalt(salt);
  decrypt_message.SetChecksum(checksum);
  decrypt_message.SetPublicR(encrypt_message.public_r());
  decrypt_message.DecryptBytes(ciphertext);
	return 0;
}


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
收藏
免费 0
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//