◎위챗 : speedseoul
http://hayageek.com/rsa-encryption-decryption-openssl-c/
In this article, I have explained how to do RSA Encryption and Decryption with OpenSSL Library in C.
1).Generate RSA keys with OpenSSL
2).Public Encryption and Private Decryption
3).Private Encryption and Public Decryption.
4).Encryption and Decryption Example code.
Use the below command to generate RSA keys with length of 2048.
1 | openssl genrsa -out private .pem 2048 |
Extract public key from private.pem with the following command.
1 | openssl rsa - in private.pem -outform PEM -pubout -out public.pem |
public.pem is RSA public key in PEM format.
private.pem is RSA private key in PEM format.
Below is the OpenSSL API for Public encryption and Private decryption.
1 2 3 4 5 | int RSA_public_encrypt(int flen, unsigned char *from, unsigned char *to, RSA *rsa, int padding); int RSA_private_decrypt(int flen, unsigned char *from, unsigned char *to, RSA *rsa, int padding); |
2.1 Preparing RSA Structure
For encryption and decryption we need to prepare RSA structure. Use the below function to create RSA with key buffer.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | RSA * createRSA(unsigned char * key, int public ) { RSA *rsa= NULL; BIO *keybio ; keybio = BIO_new_mem_buf(key, -1); if (keybio==NULL) { printf ( "Failed to create key BIO" ); return 0; } if ( public ) { rsa = PEM_read_bio_RSA_PUBKEY(keybio, &rsa,NULL, NULL); } else { rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa,NULL, NULL); } return rsa; } |
Usage for public key: createRSA(“PUBLIC_KEY_BUFFER”,1);
Usage for private key: createRSA(“PRIVATE_KEY_BUFFER”,0);
If you want to create RSA with key file name, you can use this function
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | RSA * createRSAWithFilename( char * filename, int public ) { FILE * fp = fopen (filename, "rb" ); if (fp == NULL) { printf ( "Unable to open file %s \n" ,filename); return NULL; } RSA *rsa= RSA_new() ; if ( public ) { rsa = PEM_read_RSA_PUBKEY(fp, &rsa,NULL, NULL); } else { rsa = PEM_read_RSAPrivateKey(fp, &rsa,NULL, NULL); } return rsa; } |
2.1 Public Key Encryption.
For encryption we can use padding, below is the list of supported paddings.
RSA_PKCS1_PADDING
PKCS #1 v1.5 padding. This currently is the most widely used mode.
RSA_PKCS1_OAEP_PADDING
EME-OAEP as defined in PKCS #1 v2.0 with SHA-1, MGF1 and an empty encoding parameter. This mode is recommended for all new applications.
RSA_SSLV23_PADDING
PKCS #1 v1.5 padding with an SSL-specific modification that denotes that the server is SSL3 capable.
RSA_NO_PADDING
Raw RSA encryption. This mode should only be used to implement cryptographically sound padding modes in the application code. Encrypting user data directly with RSA is insecure.
You can use the below method, to encrypt the data with public key.
1 2 3 4 5 6 7 8 | int padding = RSA_PKCS1_PADDING; int public_encrypt(unsigned char * data,int data_len,unsigned char * key, unsigned char *encrypted) { RSA * rsa = createRSA(key,1); int result = RSA_public_encrypt(data_len,data,encrypted,rsa,padding); return result; } |
Note: public key encryption supports all the paddings.
2.2 Private Decryption.
You can use the below method to decrypt the data with private key
1 2 3 4 5 6 | int private_decrypt(unsigned char * enc_data, int data_len,unsigned char * key, unsigned char *decrypted) { RSA * rsa = createRSA(key,0); int result = RSA_private_decrypt(data_len,enc_data,decrypted,rsa,padding); return result; } |
Below is the OpenSSL API for private encryption and public decryption.
1 2 3 4 5 | int RSA_private_encrypt( int flen, unsigned char *from, unsigned char *to, RSA *rsa, int padding); int RSA_public_decrypt( int flen, unsigned char *from, unsigned char *to, RSA *rsa, int padding); |
Note: private key encryption supports only these paddings. RSA_PKCS1_PADDING and RSA_NO_PADDING.
3.1 Private Key Encryption.
You can use the below function for private key encryption.
1 2 3 4 5 6 | int private_encrypt(unsigned char * data, int data_len,unsigned char * key, unsigned char *encrypted) { RSA * rsa = createRSA(key,0); int result = RSA_private_encrypt(data_len,data,encrypted,rsa,padding); return result; } |
3.2 Public Key Decryption.
You can use the below function for public key decryption.
1 2 3 4 5 6 | int public_decrypt(unsigned char * enc_data,int data_len,unsigned char * key, unsigned char *decrypted) { RSA * rsa = createRSA(key,1); int result = RSA_public_decrypt(data_len,enc_data,decrypted,rsa,padding); return result; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 | #include <openssl/pem.h> #include <openssl/ssl.h> #include <openssl/rsa.h> #include <openssl/evp.h> #include <openssl/bio.h> #include <openssl/err.h> #include <stdio.h> int padding = RSA_PKCS1_PADDING; RSA * createRSA(unsigned char * key, int public ) { RSA *rsa= NULL; BIO *keybio ; keybio = BIO_new_mem_buf(key, -1); if (keybio==NULL) { printf ( "Failed to create key BIO" ); return 0; } if ( public ) { 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; } int public_encrypt(unsigned char * data, int data_len,unsigned char * key, unsigned char *encrypted) { RSA * rsa = createRSA(key,1); int result = RSA_public_encrypt(data_len,data,encrypted,rsa,padding); return result; } int private_decrypt(unsigned char * enc_data, int data_len,unsigned char * key, unsigned char *decrypted) { RSA * rsa = createRSA(key,0); int result = RSA_private_decrypt(data_len,enc_data,decrypted,rsa,padding); return result; } int private_encrypt(unsigned char * data, int data_len,unsigned char * key, unsigned char *encrypted) { RSA * rsa = createRSA(key,0); int result = RSA_private_encrypt(data_len,data,encrypted,rsa,padding); return result; } int public_decrypt(unsigned char * enc_data, int data_len,unsigned char * key, unsigned char *decrypted) { RSA * rsa = createRSA(key,1); int result = RSA_public_decrypt(data_len,enc_data,decrypted,rsa,padding); return result; } void printLastError( char *msg) { char * err = malloc (130);; ERR_load_crypto_strings(); ERR_error_string(ERR_get_error(), err); printf ( "%s ERROR: %s\n" ,msg, err); free (err); } int main(){ char plainText[2048/8] = "Hello this is Ravi" ; //key length : 2048 char publicKey[]= "-----BEGIN PUBLIC KEY-----\n" \ "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy8Dbv8prpJ/0kKhlGeJY\n" \ "ozo2t60EG8L0561g13R29LvMR5hyvGZlGJpmn65+A4xHXInJYiPuKzrKUnApeLZ+\n" \ "vw1HocOAZtWK0z3r26uA8kQYOKX9Qt/DbCdvsF9wF8gRK0ptx9M6R13NvBxvVQAp\n" \ "fc9jB9nTzphOgM4JiEYvlV8FLhg9yZovMYd6Wwf3aoXK891VQxTr/kQYoq1Yp+68\n" \ "i6T4nNq7NWC+UNVjQHxNQMQMzU6lWCX8zyg3yH88OAQkUXIXKfQ+NkvYQ1cxaMoV\n" \ "PpY72+eVthKzpMeyHkBn7ciumk5qgLTEJAfWZpe4f4eFZj/Rc8Y8Jj2IS5kVPjUy\n" \ "wQIDAQAB\n" \ "-----END PUBLIC KEY-----\n" ; char privateKey[]= "-----BEGIN RSA PRIVATE KEY-----\n" \ "MIIEowIBAAKCAQEAy8Dbv8prpJ/0kKhlGeJYozo2t60EG8L0561g13R29LvMR5hy\n" \ "vGZlGJpmn65+A4xHXInJYiPuKzrKUnApeLZ+vw1HocOAZtWK0z3r26uA8kQYOKX9\n" \ "Qt/DbCdvsF9wF8gRK0ptx9M6R13NvBxvVQApfc9jB9nTzphOgM4JiEYvlV8FLhg9\n" \ "yZovMYd6Wwf3aoXK891VQxTr/kQYoq1Yp+68i6T4nNq7NWC+UNVjQHxNQMQMzU6l\n" \ "WCX8zyg3yH88OAQkUXIXKfQ+NkvYQ1cxaMoVPpY72+eVthKzpMeyHkBn7ciumk5q\n" \ "gLTEJAfWZpe4f4eFZj/Rc8Y8Jj2IS5kVPjUywQIDAQABAoIBADhg1u1Mv1hAAlX8\n" \ "omz1Gn2f4AAW2aos2cM5UDCNw1SYmj+9SRIkaxjRsE/C4o9sw1oxrg1/z6kajV0e\n" \ "N/t008FdlVKHXAIYWF93JMoVvIpMmT8jft6AN/y3NMpivgt2inmmEJZYNioFJKZG\n" \ "X+/vKYvsVISZm2fw8NfnKvAQK55yu+GRWBZGOeS9K+LbYvOwcrjKhHz66m4bedKd\n" \ "gVAix6NE5iwmjNXktSQlJMCjbtdNXg/xo1/G4kG2p/MO1HLcKfe1N5FgBiXj3Qjl\n" \ "vgvjJZkh1as2KTgaPOBqZaP03738VnYg23ISyvfT/teArVGtxrmFP7939EvJFKpF\n" \ "1wTxuDkCgYEA7t0DR37zt+dEJy+5vm7zSmN97VenwQJFWMiulkHGa0yU3lLasxxu\n" \ "m0oUtndIjenIvSx6t3Y+agK2F3EPbb0AZ5wZ1p1IXs4vktgeQwSSBdqcM8LZFDvZ\n" \ "uPboQnJoRdIkd62XnP5ekIEIBAfOp8v2wFpSfE7nNH2u4CpAXNSF9HsCgYEA2l8D\n" \ "JrDE5m9Kkn+J4l+AdGfeBL1igPF3DnuPoV67BpgiaAgI4h25UJzXiDKKoa706S0D\n" \ "4XB74zOLX11MaGPMIdhlG+SgeQfNoC5lE4ZWXNyESJH1SVgRGT9nBC2vtL6bxCVV\n" \ "WBkTeC5D6c/QXcai6yw6OYyNNdp0uznKURe1xvMCgYBVYYcEjWqMuAvyferFGV+5\n" \ "nWqr5gM+yJMFM2bEqupD/HHSLoeiMm2O8KIKvwSeRYzNohKTdZ7FwgZYxr8fGMoG\n" \ "PxQ1VK9DxCvZL4tRpVaU5Rmknud9hg9DQG6xIbgIDR+f79sb8QjYWmcFGc1SyWOA\n" \ "SkjlykZ2yt4xnqi3BfiD9QKBgGqLgRYXmXp1QoVIBRaWUi55nzHg1XbkWZqPXvz1\n" \ "I3uMLv1jLjJlHk3euKqTPmC05HoApKwSHeA0/gOBmg404xyAYJTDcCidTg6hlF96\n" \ "ZBja3xApZuxqM62F6dV4FQqzFX0WWhWp5n301N33r0qR6FumMKJzmVJ1TA8tmzEF\n" \ "yINRAoGBAJqioYs8rK6eXzA8ywYLjqTLu/yQSLBn/4ta36K8DyCoLNlNxSuox+A5\n" \ "w6z2vEfRVQDq4Hm4vBzjdi3QfYLNkTiTqLcvgWZ+eX44ogXtdTDO7c+GeMKWz4XX\n" \ "uJSUVL5+CVjKLjZEJ6Qc2WZLl94xSwL71E41H4YciVnSCQxVc4Jw\n" \ "-----END RSA PRIVATE KEY-----\n" ; unsigned char encrypted[4098]={}; unsigned char decrypted[4098]={}; int encrypted_length= public_encrypt(plainText, strlen (plainText),publicKey,encrypted); if (encrypted_length == -1) { printLastError( "Public Encrypt failed " ); exit (0); } printf ( "Encrypted length =%d\n" ,encrypted_length); int decrypted_length = private_decrypt(encrypted,encrypted_length,privateKey, decrypted); if (decrypted_length == -1) { printLastError( "Private Decrypt failed " ); exit (0); } printf ( "Decrypted Text =%s\n" ,decrypted); printf ( "Decrypted Length =%d\n" ,decrypted_length); encrypted_length= private_encrypt(plainText, strlen (plainText),privateKey,encrypted); if (encrypted_length == -1) { printLastError( "Private Encrypt failed" ); exit (0); } printf ( "Encrypted length =%d\n" ,encrypted_length); decrypted_length = public_decrypt(encrypted,encrypted_length,publicKey, decrypted); if (decrypted_length == -1) { printLastError( "Public Decrypt failed" ); exit (0); } printf ( "Decrypted Text =%s\n" ,decrypted); printf ( "Decrypted Length =%d\n" ,decrypted_length); } |