Created
September 24, 2019 07:39
-
-
Save Erfan-Ahmadi/ba03eadd1be2262a849e143146a2de99 to your computer and use it in GitHub Desktop.
OpenSSL Digital Signature Code (Sign/Verify)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <openssl/aes.h> | |
#include <openssl/evp.h> | |
#include <openssl/rsa.h> | |
#include <openssl/pem.h> | |
#include <openssl/ssl.h> | |
#include <openssl/bio.h> | |
#include <openssl/err.h> | |
#include <stdio.h> | |
#define KEY_LENGTH 2048 | |
#define PUB_EXP 3 | |
#include <string.h> | |
static const unsigned char base64_table[65] = | |
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | |
/** | |
* base64_encode - Base64 encode | |
* @src: Data to be encoded | |
* @len: Length of the data to be encoded | |
* @out_len: Pointer to output length variable, or %NULL if not used | |
* Returns: Allocated buffer of out_len bytes of encoded data, | |
* or %NULL on failure | |
* | |
* Caller is responsible for freeing the returned buffer. Returned buffer is | |
* nul terminated to make it easier to use as a C string. The nul terminator is | |
* not included in out_len. | |
*/ | |
unsigned char * base64_encode(const unsigned char *src, size_t len, | |
size_t *out_len) | |
{ | |
unsigned char *out, *pos; | |
const unsigned char *end, *in; | |
size_t olen; | |
int line_len; | |
olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */ | |
olen += olen / 72; /* line feeds */ | |
olen++; /* nul termination */ | |
if (olen < len) | |
return NULL; /* integer overflow */ | |
out = malloc(olen); | |
if (out == NULL) | |
return NULL; | |
end = src + len; | |
in = src; | |
pos = out; | |
line_len = 0; | |
while (end - in >= 3) { | |
*pos++ = base64_table[in[0] >> 2]; | |
*pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)]; | |
*pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)]; | |
*pos++ = base64_table[in[2] & 0x3f]; | |
in += 3; | |
line_len += 4; | |
if (line_len >= 72) { | |
*pos++ = '\n'; | |
line_len = 0; | |
} | |
} | |
if (end - in) { | |
*pos++ = base64_table[in[0] >> 2]; | |
if (end - in == 1) { | |
*pos++ = base64_table[(in[0] & 0x03) << 4]; | |
*pos++ = '='; | |
} else { | |
*pos++ = base64_table[((in[0] & 0x03) << 4) | | |
(in[1] >> 4)]; | |
*pos++ = base64_table[(in[1] & 0x0f) << 2]; | |
} | |
*pos++ = '='; | |
line_len += 4; | |
} | |
if (line_len) | |
*pos++ = '\n'; | |
*pos = '\0'; | |
if (out_len) | |
*out_len = pos - out; | |
return out; | |
} | |
/** | |
* base64_decode - Base64 decode | |
* @src: Data to be decoded | |
* @len: Length of the data to be decoded | |
* @out_len: Pointer to output length variable | |
* Returns: Allocated buffer of out_len bytes of decoded data, | |
* or %NULL on failure | |
* | |
* Caller is responsible for freeing the returned buffer. | |
*/ | |
unsigned char * base64_decode(const unsigned char *src, size_t len, | |
size_t *out_len) | |
{ | |
unsigned char dtable[256], *out, *pos, block[4], tmp; | |
size_t i, count, olen; | |
int pad = 0; | |
memset(dtable, 0x80, 256); | |
for (i = 0; i < sizeof(base64_table) - 1; i++) | |
dtable[base64_table[i]] = (unsigned char) i; | |
dtable['='] = 0; | |
count = 0; | |
for (i = 0; i < len; i++) { | |
if (dtable[src[i]] != 0x80) | |
count++; | |
} | |
if (count == 0 || count % 4) | |
return NULL; | |
olen = count / 4 * 3; | |
pos = out = malloc(olen); | |
if (out == NULL) | |
return NULL; | |
count = 0; | |
for (i = 0; i < len; i++) { | |
tmp = dtable[src[i]]; | |
if (tmp == 0x80) | |
continue; | |
if (src[i] == '=') | |
pad++; | |
block[count] = tmp; | |
count++; | |
if (count == 4) { | |
*pos++ = (block[0] << 2) | (block[1] >> 4); | |
*pos++ = (block[1] << 4) | (block[2] >> 2); | |
*pos++ = (block[2] << 6) | block[3]; | |
count = 0; | |
if (pad) { | |
if (pad == 1) | |
pos--; | |
else if (pad == 2) | |
pos -= 2; | |
else { | |
/* Invalid padding */ | |
free(out); | |
return NULL; | |
} | |
break; | |
} | |
} | |
} | |
*out_len = pos - out; | |
return out; | |
} | |
RSA* createRSA(unsigned char* key, int pub) | |
{ | |
RSA* rsa = NULL; | |
BIO* keybio; | |
keybio = BIO_new_mem_buf(key, -1); | |
if (keybio == NULL) | |
{ | |
printf("Failed to create key BIO"); | |
return 0; | |
} | |
if (pub) | |
{ | |
rsa = PEM_read_bio_RSA_PUBKEY(keybio, &rsa, NULL, NULL); | |
} | |
else | |
{ | |
rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa, NULL, NULL); | |
} | |
if (rsa == NULL) | |
{ | |
printf("Failed to create RSA"); | |
} | |
return rsa; | |
} | |
char* sign(const char* pri_key, const char* msg, size_t* len) | |
{ | |
RSA* rsa = createRSA(pri_key, 0); | |
EVP_PKEY* priKey = EVP_PKEY_new(); | |
EVP_PKEY_assign_RSA(priKey, rsa); | |
EVP_MD_CTX *mdctx = NULL; | |
int ret = 0; | |
int slen = 0; | |
unsigned char* sig; | |
/* Create the Message Digest Context */ | |
if(!(mdctx = EVP_MD_CTX_create())) goto err; | |
/* Initialise the EVP_DigestSignInitDigestSign operation - SHA-1 has been selected as the message digest function in this example */ | |
if(1 != EVP_DigestSignInit(mdctx, NULL, EVP_sha1(), NULL, priKey)) goto err; | |
/* Call update with the message */ | |
if(1 != EVP_DigestSignUpdate(mdctx, msg, strlen(msg))) goto err; | |
/* Finalise the DigestSign operation */ | |
/* First call EVP_DigestSignFinal with a NULL sig parameter to obtain the length of the | |
* signature. Length is returned in slen */ | |
if(1 != EVP_DigestSignFinal(mdctx, NULL, &slen)) goto err; | |
printf("(%d)\n", slen); | |
/* Allocate memory for the signature based on size in slen */ | |
if(!(sig = OPENSSL_malloc(sizeof(unsigned char) * (slen)))) goto err; | |
/* Obtain the signature */ | |
if(1 != EVP_DigestSignFinal(mdctx, sig, &slen)) goto err; | |
/* Success */ | |
ret = 1; | |
err: | |
if(ret != 1) | |
{ | |
/* Do some error handling */ | |
} | |
/* Clean up */ | |
if(sig && !ret) | |
{ | |
OPENSSL_free(sig); | |
} | |
if(mdctx) | |
{ | |
EVP_MD_CTX_destroy(mdctx); | |
} | |
char* base64 = base64_encode(sig, slen, len); | |
OPENSSL_free(sig); | |
return base64; | |
} | |
int verify(const char* pub_key, const char* signature, size_t siglen, const char* msg) | |
{ | |
size_t slen; | |
unsigned char* sig = base64_decode(signature, siglen, &slen); | |
RSA* rsa = createRSA(pub_key, 1); | |
EVP_PKEY* pubKey = EVP_PKEY_new(); | |
EVP_PKEY_assign_RSA(pubKey, rsa); | |
EVP_MD_CTX *mdctx = NULL; | |
/* Create the Message Digest Context */ | |
if(!(mdctx = EVP_MD_CTX_create())) | |
return 0; | |
/* Initialize `key` with a public key */ | |
if(1 != EVP_DigestVerifyInit(mdctx, NULL, EVP_sha1(), NULL, pubKey)) | |
return 0; | |
/* Initialize `key` with a public key */ | |
if(1 != EVP_DigestVerifyUpdate(mdctx, msg, strlen(msg))) | |
return 0; | |
if(1 == EVP_DigestVerifyFinal(mdctx, sig, slen)) | |
{ | |
if(mdctx) | |
{ | |
EVP_MD_CTX_destroy(mdctx); | |
} | |
return 1; | |
} | |
else | |
{ | |
if(mdctx) | |
{ | |
EVP_MD_CTX_destroy(mdctx); | |
} | |
return 0; | |
} | |
} | |
#define GENKEY 0 | |
int main() | |
{ | |
// Generate Key | |
size_t pri_len; // Length of private key | |
size_t pub_len; // Length of public key | |
char* pri_key; // Private key | |
char* pub_key; // Public key | |
if(GENKEY) | |
{ | |
RSA *keypair = RSA_generate_key(KEY_LENGTH, PUB_EXP, NULL, NULL); | |
// To get the C-string PEM form: | |
BIO *pri = BIO_new(BIO_s_mem()); | |
BIO *pub = BIO_new(BIO_s_mem()); | |
PEM_write_bio_RSAPrivateKey(pri, keypair, NULL, NULL, 0, NULL, NULL); | |
PEM_write_bio_RSA_PUBKEY(pub, keypair); | |
pri_len = BIO_pending(pri); | |
pub_len = BIO_pending(pub); | |
pri_key = malloc(pri_len + 1); | |
pub_key = malloc(pub_len + 1); | |
BIO_read(pri, pri_key, pri_len); | |
BIO_read(pub, pub_key, pub_len); | |
} | |
pri_key = "-----BEGIN RSA PRIVATE KEY-----\n\ | |
MIIEogIBAAKCAQEAvoPZEZmJ5+IP5ZOtVY0lGINnnCwlqI4taw/ZXgqcfrnZXoOH\ | |
UXF1cb831MiPmdOff/JQsZ/yEpGCO4GligH7nEyR35PYFqQ7EPkn7LdnucO0jnnz\ | |
H509pUMJPyWYHQcQvf4Tm/cIISPFCnT93oP1T6dcEp3p/ndcLoqO6TfzY5JR2XHi\ | |
0QXcjm8aO2oEGADVh6fcIAWizGe3Ux+O+VR6PuaDKs+I1XqxZm2isq2bj4TDNZ84\ | |
/iZudEvAyMEfEv9qGlY8kfGmAUVWweNkMdj1cM6wybmQ4eTBlBcDgVuEG/65ik6T\ | |
CBNK8Ho9bNaKgAUeCxhw1gaOzNez1+JiTq9DUwIBAwKCAQB/ApC2Zlvv7AqZDR45\ | |
CMNlrO+9csPFtB5HX+Y+sb2p0TuUV6+LoPj2f3qN2wpmjRT/9uB2aqFhtlbSVm5c\ | |
AVJoMwvqYpAPGCdgphqdz5p71820UUy/vikY11t/bmVor2B+qWJn+gVrbS4G+Kk/\ | |
AqOKb5K3E/FUT5LJsbSbeqJCYGOZS+B7otttUmJGhPdUajN9mwBEx1j9sBwP71U1\ | |
BZ46P32qnaW7ZVFdtSlr1hfQ+tRKHcLqmJiuU1AzOnUltbTiYpaOuR3MD2fSrfG0\ | |
7/xcuY367Nxy4ZciGd2+LmldnNJjSPMmBVxJi5+Zf66MXT/awun1vVRN0bN8tpQW\ | |
78ibAoGBAPb4uFxY2iVM4BrCU0XropNh3kMgdlv/RB+ABMV46brhLXoxSlWotQJB\ | |
WO2Pes0iRye3GMpTkBnxLD3xrGfg6pov+ur91r7BPnCXefVl9DjRP+3G4gxjOIww\ | |
08knqUiJeaUoO7+nni/nXeP8TKSxLTh3nf79bKTBf92vGttsNF5NAoGBAMV6x7W+\ | |
t24dk2wPT0stvvTpYRiYZEFQm227M8mw4lIGWcx5mLqTrbUYhPcBcaqzxV0PWcpK\ | |
sW99ooqKPQd5hECWx2++BTqN78puZIQ8fMIUeG4KdDnSWdKwHG28bJ2GGdjNJWan\ | |
bRCayuoKSl/8TAXLVhLn/euWnUjttajAEzgfAoGBAKSl0D2QkW4zQBHW4i6dFwzr\ | |
6YIVpD1U2BUAAy5Qm9Hrc6bLhuPFzgGA5fO0/IjBhMUkuzGNCrv2HX6hHZqV8bwf\ | |
/JypOdSA1EsPpqOZTXs2Kp6ElrLs0F114oYacNsGURjFfSpvvsqaPpf9iG3Lc3r6\ | |
aVSo8xiA/+kfZzzyzZQzAoGBAIOnL85/JPQTt51fijIef03w62W67YDgZ558zTEg\ | |
luFZkTL7uycNHni7A09WS8cig5NfkTGHIPT+bFxcKK+mWCsPL5/UA3xen9xJmFgo\ | |
UywNpZ6xotE25ox1aEkoSGkEETszbkRvngsR3JwG3D/9iAPc5AyaqUe5vjCeeRsq\ | |
t3q/AoGARhAsxx3XELO6xfrFhuC/upzkzpjNpKwDRT96y7z5TTcxb4/eQu1fr3Lx\ | |
PNNM1MMzON50A+H+y/uXkJAy6SKwQIsAUl+69OfYCRxqoYMMspuSACCNSPHFdlok\ | |
pQZep5g/u3eXHTCHzJA2nfhytJyqzfJ/S093Z2mCd5mmv2SZZXU=\n\ | |
-----END RSA PRIVATE KEY-----"; | |
pub_key = "-----BEGIN PUBLIC KEY-----\n\ | |
MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEAvoPZEZmJ5+IP5ZOtVY0l\ | |
GINnnCwlqI4taw/ZXgqcfrnZXoOHUXF1cb831MiPmdOff/JQsZ/yEpGCO4GligH7\ | |
nEyR35PYFqQ7EPkn7LdnucO0jnnzH509pUMJPyWYHQcQvf4Tm/cIISPFCnT93oP1\ | |
T6dcEp3p/ndcLoqO6TfzY5JR2XHi0QXcjm8aO2oEGADVh6fcIAWizGe3Ux+O+VR6\ | |
PuaDKs+I1XqxZm2isq2bj4TDNZ84/iZudEvAyMEfEv9qGlY8kfGmAUVWweNkMdj1\ | |
cM6wybmQ4eTBlBcDgVuEG/65ik6TCBNK8Ho9bNaKgAUeCxhw1gaOzNez1+JiTq9D\ | |
UwIBAw==\n\ | |
-----END PUBLIC KEY-----"; | |
char* msg = "hi hello how are you?"; | |
printf("Message= %s\n", msg); | |
size_t slen; | |
char* sig = sign(pri_key, msg, &slen); | |
printf("\nSignature:\n%s\n", sig); | |
int valid = verify(pub_key, sig, slen, msg); | |
if(valid) | |
{ | |
printf("\n---VERIFICATION SUCCESS---\n"); | |
} | |
else | |
{ | |
printf("\n---VERIFICATION FAILED---\n"); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment