Skip to content

Instantly share code, notes, and snippets.

@Erfan-Ahmadi
Created September 24, 2019 07:39
Show Gist options
  • Save Erfan-Ahmadi/ba03eadd1be2262a849e143146a2de99 to your computer and use it in GitHub Desktop.
Save Erfan-Ahmadi/ba03eadd1be2262a849e143146a2de99 to your computer and use it in GitHub Desktop.
OpenSSL Digital Signature Code (Sign/Verify)
#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