ECDSACrypto.cpp 6.63 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/*
    Copyright (C) 2019-Present SKALE Labs

    This file is part of sgxwallet.

    sgxwallet is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published
    by the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    sgxwallet is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with sgxwallet.  If not, see <https://www.gnu.org/licenses/>.

    @file ECDSACrypto.cpp
    @author Stan Kladko
    @date 2019
*/
23 24 25

#include "sgxwallet.h"

26
#include "SGXException.h"
27 28

#include <iostream>
kladko's avatar
kladko committed
29 30
#include <fstream>

31 32
#include <gmp.h>
#include <random>
33

kladko's avatar
kladko committed
34

35
#include "spdlog/spdlog.h"
kladko's avatar
kladko committed
36 37
#include "common.h"

kladko's avatar
kladko committed
38

kladko's avatar
kladko committed
39 40
#include "secure_enclave/Verify.h"

kladko's avatar
kladko committed
41
#include "BLSCrypto.h"
kladko's avatar
kladko committed
42

kladko's avatar
kladko committed
43
#include "ECDSACrypto.h"
44

45

46 47 48 49
string concatPubKeyWith0x(char *pub_key_x, char *pub_key_y) {
    string px = pub_key_x;
    string py = pub_key_y;
    string result = "0x" + px + py;
50
    return result;
51 52
}

kladko's avatar
kladko committed
53 54
void fillRandomBuffer(vector<unsigned char> &_buffer) {
    ifstream devRandom("/dev/urandom", ios::in | ios::binary);
kladko's avatar
kladko committed
55
    devRandom.exceptions(ifstream::failbit | ifstream::badbit);
kladko's avatar
kladko committed
56
    devRandom.read((char *) _buffer.data(), _buffer.size());
kladko's avatar
kladko committed
57 58 59
    devRandom.close();
}

kladko's avatar
kladko committed
60
vector <string> genECDSAKey() {
kladko's avatar
kladko committed
61
    vector<char> errMsg(1024, 0);
62
    int errStatus = 0;
kladko's avatar
kladko committed
63 64 65
    vector <uint8_t> encr_pr_key(1024, 0);
    vector<char> pub_key_x(1024, 0);
    vector<char> pub_key_y(1024, 0);
kladko's avatar
kladko committed
66

67 68
    uint32_t enc_len = 0;

69 70 71
    status = trustedGenerateEcdsaKeyAES(eid, &errStatus,
                                        errMsg.data(), encr_pr_key.data(), &enc_len,
                                        pub_key_x.data(), pub_key_y.data());
72

73
    if (status != SGX_SUCCESS || errStatus != 0) {
74
        spdlog::error("RPCException thrown with status {}", status);
kladko's avatar
kladko committed
75
        throw SGXException(status, errMsg.data());
76
    }
kladko's avatar
kladko committed
77
    vector <string> keys(3);
78

kladko's avatar
kladko committed
79 80 81
    vector<char> hexEncrKey(BUF_LEN * 2, 0);
    carray2Hex(encr_pr_key.data(), enc_len, hexEncrKey.data());
    keys.at(0) = hexEncrKey.data();
kladko's avatar
kladko committed
82
    keys.at(1) = string(pub_key_x.data()) + string(pub_key_y.data());
83

kladko's avatar
kladko committed
84
    vector<unsigned char> randBuffer(32, 0);
kladko's avatar
kladko committed
85
    fillRandomBuffer(randBuffer);
86

kladko's avatar
kladko committed
87
    vector<char> rand_str(64, 0);
88

kladko's avatar
kladko committed
89
    carray2Hex(randBuffer.data(), 32, rand_str.data());
90

kladko's avatar
kladko committed
91
    keys.at(2) = rand_str.data();
92

kladko's avatar
kladko committed
93
    CHECK_STATE(keys.at(2).size() == 64);
94

95
    return keys;
96 97
}

kladko's avatar
kladko committed
98
string getECDSAPubKey(const char *_encryptedKeyHex) {
99 100 101
    vector<char> errMsg(BUF_LEN, 0);
    vector<char> pubKeyX(BUF_LEN, 0);
    vector<char> pubKeyY(BUF_LEN, 0);
kladko's avatar
kladko committed
102
    vector <uint8_t> encrPrKey(BUF_LEN, 0);
103

104
    int errStatus = 0;
105 106 107
    uint64_t enc_len = 0;

    if (!hex2carray(_encryptedKeyHex, &enc_len, encrPrKey.data())) {
108
        throw SGXException(INVALID_HEX, "Invalid encryptedKeyHex");
109 110
    }

111 112
    status = trustedGetPublicEcdsaKeyAES(eid, &errStatus,
                                         errMsg.data(), encrPrKey.data(), enc_len, pubKeyX.data(), pubKeyY.data());
113

114
    if (errStatus != 0) {
115
        throw SGXException(-666, errMsg.data());
116
    }
117 118 119 120 121

    if (status != SGX_SUCCESS) {
        spdlog::error("failed to get ECDSA public key {}", status);
        throw SGXException(666, "failed to get ECDSA public key");
    }
122 123
    string pubKey = string(pubKeyX.data()) + string(pubKeyY.data());//concatPubKeyWith0x(pub_key_x, pub_key_y);//

kladko's avatar
kladko committed
124 125 126 127 128 129

    if (pubKey.size() != 128) {
        spdlog::error("Incorrect pub key size", status);
        throw SGXException(666, "Incorrect pub key size");
    }

130
    return pubKey;
131 132
}

kladko's avatar
kladko committed
133
bool verifyECDSASig(string& pubKeyStr, const char *hashHex, const char *signatureR,
134
        const char *signatureS, int base) {
kladko's avatar
kladko committed
135
    bool result = false;
kladko's avatar
kladko committed
136 137 138

    signature sig = signature_init();

139 140
    auto x = pubKeyStr.substr(0, 64);
    auto y = pubKeyStr.substr(64, 128);
kladko's avatar
kladko committed
141 142 143
    domain_parameters curve = domain_parameters_init();
    domain_parameters_load_curve(curve, secp256k1);
    point publicKey = point_init();
144

kladko's avatar
kladko committed
145 146 147 148 149 150
    mpz_t msgMpz;
    mpz_init(msgMpz);
    if (mpz_set_str(msgMpz, hashHex, 16) == -1) {
        spdlog::error("invalid message hash {}", hashHex);
        goto clean;
    }
kladko's avatar
kladko committed
151

152
    if (signature_set_str(sig, signatureR, signatureS, base) != 0) {
153 154 155
        spdlog::error("Failed to set str signature");
        goto clean;
    }
kladko's avatar
kladko committed
156

157
    point_set_hex(publicKey, x.c_str(), y.c_str());
kladko's avatar
kladko committed
158 159 160 161
    if (!signature_verify(msgMpz, sig, publicKey, curve)) {
        spdlog::error("ECDSA sig not verified");
        goto clean;
    }
kladko's avatar
kladko committed
162

kladko's avatar
kladko committed
163 164
    result = true;

kladko's avatar
kladko committed
165
    clean:
kladko's avatar
kladko committed
166

kladko's avatar
kladko committed
167 168 169 170
    mpz_clear(msgMpz);
    domain_parameters_clear(curve);
    point_clear(publicKey);
    signature_free(sig);
kladko's avatar
kladko committed
171

kladko's avatar
kladko committed
172
    return result;
kladko's avatar
kladko committed
173
}
kladko's avatar
kladko committed
174

kladko's avatar
kladko committed
175
vector <string> ecdsaSignHash(const char *encryptedKeyHex, const char *hashHex, int base) {
kladko's avatar
kladko committed
176
    vector <string> signatureVector(3);
177

kladko's avatar
kladko committed
178 179 180 181 182 183 184
    vector<char> errMsg(1024, 0);
    int errStatus = 0;
    vector<char> signatureR(1024, 0);
    vector<char> signatureS(1024, 0);
    vector<uint8_t> encryptedKey(1024, 0);
    uint8_t signatureV = 0;
    uint64_t decLen = 0;
185

kladko's avatar
kladko committed
186
    string pubKeyStr = "";
187

kladko's avatar
kladko committed
188
    shared_ptr<SGXException> exception = NULL;
189

kladko's avatar
kladko committed
190 191 192
    if (!hex2carray(encryptedKeyHex, &decLen, encryptedKey.data())) {
        exception = make_shared<SGXException>(INVALID_HEX, "Invalid encryptedKeyHex");
        goto clean;
193 194
    }

kladko's avatar
kladko committed
195
    pubKeyStr = getECDSAPubKey(encryptedKeyHex);
kladko's avatar
kladko committed
196

197 198 199 200
    status = trustedEcdsaSignAES(eid, &errStatus,
            errMsg.data(), encryptedKey.data(), decLen, (unsigned char *) hashHex,
                                 signatureR.data(),
                                 signatureS.data(), &signatureV, base);
201

kladko's avatar
kladko committed
202 203
    if (errStatus != 0) {
        exception = make_shared<SGXException>(666, errMsg.data());
kladko's avatar
kladko committed
204 205 206
        goto clean;
    }

kladko's avatar
kladko committed
207 208 209
    if (status != SGX_SUCCESS) {
        spdlog::error("failed to sign {}", status);
        exception = make_shared<SGXException>(666, "failed to sign");
kladko's avatar
kladko committed
210 211
        goto clean;
    }
kladko's avatar
kladko committed
212
    signatureVector.at(0) = to_string(signatureV);
kladko's avatar
kladko committed
213
    if (base == 16) {
kladko's avatar
kladko committed
214 215
        signatureVector.at(1) = "0x" + string(signatureR.data());
        signatureVector.at(2) = "0x" + string(signatureS.data());
kladko's avatar
kladko committed
216
    } else {
kladko's avatar
kladko committed
217 218
        signatureVector.at(1) = string(signatureR.data());
        signatureVector.at(2) = string(signatureS.data());
kladko's avatar
kladko committed
219
    }
kladko's avatar
kladko committed
220

kladko's avatar
kladko committed
221
    /* Now verify signature */
kladko's avatar
kladko committed
222

223
    if (!verifyECDSASig(pubKeyStr, hashHex, signatureR.data(), signatureS.data(), base)) {
kladko's avatar
kladko committed
224 225 226
        exception = make_shared<SGXException>(667, "ECDSA did not verify");
        goto clean;
    }
kladko's avatar
kladko committed
227 228 229

    clean:

kladko's avatar
kladko committed
230 231
    if (exception)
        throw *exception;
232

kladko's avatar
kladko committed
233
    return signatureVector;
234
}