Cryptography - Key Generation



Key Management

The administration and security of the keys used to encrypt and decrypt data is referred to as key management. This covers −

  • Generation

  • Storage

  • Distribution

  • Revocation

Key management Life cycle

Key Generation

People use a variety of online softwares and websites these days to transfer data between locations. Cryptographic-based methods are used in software and applications to protect user data from hackers. The cryptographic algorithm's foundation is the encryption and decryption procedures, which are executed with the use of a key. While one producing key directly interprets the password, cryptographic methods use automatic key generation that begins with the user's password.

The same key is used by symmetric algorithms for both encryption and decryption. Symmetric algorithms use a second or subsidiary approach for key generation. This key generation mechanism protects the password from several types of key attacks.

In cryptography, these keys serve as the means to encode and decode the data. Tools or software designed specifically for generating keys are known as key generators or keygens.

What are keys?

In cryptography, a key is just a really large number. Cryptography relies strongly on keys, which are used in operations like hashing, encryption, and signing to give desired qualities like authenticity (confirming the source of the information), confidentiality (keeping it hidden), and integrity (preventing it from being altered).

The number of binary digits, or "bits," or 1s and 0s, required to represent a key's value is how long the key is measured. Typically, keys consist of hundreds or maybe even thousands of bits. This provides a compromise between security and computational speed; if the key is too lengthy, cryptography becomes impractical and if it is too short, it is not secure.

Key types

Keys in cryptography can be of two types:

Symmetric Keys

Data is usually encrypted and decrypted using symmetric keys. They function to securely "lock" away information (i.e., encrypt it) so that only the owner of the key may "unlock" (i.e., decrypt it), making them comparable to physical keys. The fact that the same key is used for both encryption and decryption gives rise to the term "symmetric."

Symmetric keys need to be kept secret, long, and random in order to be considered secure, or "strong." Without this secret key, an attacker is unable to decrypt the data, even if they are aware of the encryption scheme that was used. An attacker cannot guess (or "brute force") a strong key and a high-quality symmetric encryption method in a reasonable amount of time, not even with a highly powerful computer capable of trying millions of key guesses per second.

Used for encrypting and decrypting data. The key is shared by both parties.

Asymmetric Keys

Asymmetric keys are typically found in pairs, each of which consists of a "public key" and a "private key" that are linked mathematically. The public key is intended for public distribution, while the private key must be kept secret. "Public key cryptography" is made possible by these keys.

The data can be encrypted with the help of the public key by anybody, but it can only be decrypted or decoded by the owner of the private key because of the features of asymmetric keys. Sending someone a private message is benificial because all they need is your public key.

Sending someone a private message is advantageous since all they need is your public key.

Verifying a message's authenticity also can be executed via asymmetric keys. To create a "digital signature," the message is first compressed the usage of a device referred to as a "hash function," and the ensuing "fingerprint" is then encrypted with the private key. Then, all people may additionally fast and without problems decrypt this signature using the sender's public key to confirm that it produces the equal end result as hashing the message themselves; if not, most effective the owner of the associated personal key can signed it.

Key Life−Cycle

The period of time from the moment a key is created until it is completely destroyed is referred to as the key life-cycle. Many things can happen to a key in its lifetime. It may be authorised, backed up, shared, or withdrawn. Also, a key can be updated on a regular basis (that is, its value changes even though it logically remains the same with the same meta-data). This is a smart security practice because the longer a key is used, the higher chances that it will be compromised.

Generating Symmetric Keys

Symmetric keys are often created using random number generators (RNGs) or pseudorandom number generators (PRNGs).

To create random numbers, use programming libraries or built-in functions in your programming language of your choice.

Make sure that random number creation is secure and unpredictable.

Example

In this example, we use random number generation techniques to create a cryptographically strong key of a specified length. The key is then displayed in hexadecimal format, which makes it more secure by presenting the data in an unreadable form.

This approach is used for secure encryption and decryption processes.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

void generate_symmetric_key(int key_length, unsigned char *key) {
   // Generate a random key with the specified length
   for (int i = 0; i < key_length; i++) {
      key[i] = rand() % 256;
   }
}

int main() {
   // Seed the random number generator
   srand(time(NULL));

   // Create a symmetric key with a length of 32 bytes (256 bits)
   unsigned char key[32];
   generate_symmetric_key(32, key);

   // Display the key in hexadecimal format
   printf("Symmetric Key: ");
   for (int i = 0; i < 32; i++) {
      printf("%02x", key[i]);
   }
   printf("\n");

   return 0;
}

Output

The output obtained is as follows −

Symmetric Key: 4dca10e9beb45182d22c9ffb3e130770b8cfe0fd797e78d32c145495f489f741
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <iomanip>

void generate_symmetric_key(int key_length, unsigned char* key) {
   // Generate a random key with the specified length
   for (int i = 0; i < key_length; i++) {
      key[i] = rand() % 256;
   }
}

int main() {
   // Seed the random number generator
   srand(time(NULL));

   // Create a symmetric key with a length of 32 bytes (256 bits)
   unsigned char key[32];
   generate_symmetric_key(32, key);

   // Display the key in hexadecimal format
   std::cout << "Symmetric Key: ";
   for (int i = 0; i < 32; i++) {
      std::cout << std::hex << std::setw(2) << std::setfill('0') << (int)key[i];
   }
   std::cout << std::endl;

   return 0;
}

Output

The output produced is as follows −

Symmetric Key: 5a9d331717bcd96089d7c2937e274a4b3aaf85859e55793a708f7357d9ca6533
import java.security.SecureRandom;

public class SymmetricKeyGenerator {
   public static byte[] generateSymmetricKey(int keyLength) {
      // Generate a random key with the specified length
      SecureRandom secureRandom = new SecureRandom();
      byte[] key = new byte[keyLength];
      secureRandom.nextBytes(key);
      return key;
   }

   public static void main(String[] args) {
      // Create a symmetric key with a length of 32 bytes (256 bits)
      byte[] key = generateSymmetricKey(32);

      // Display the key in hexadecimal format
      System.out.print("Symmetric Key: ");
      for (byte b : key) {
         System.out.printf("%02x", b);
      }
      System.out.println();
   }
}

Output

The output obtained is as shown below −

Symmetric Key: e8e6da9310761c848c7be70c7ea7b8af13f51c949d33f741d0f0910926d86e63
import secrets

def generate_symmetric_key(key_length):
   # Generate a random key with the specified length
   key = secrets.token_bytes(key_length)
   return key

# Create a symmetric key with a length of 32 bytes (256 bits)
key = generate_symmetric_key(32)
print("Symmetric Key:", key.hex())

Output

Following is the output of the above code −

Symmetric Key: 58441e28a9515d10aa56d7f379e7320922211088a9dcd927278c42dc024d37df

Generating Asymmetric Key

A public key and a private key are the two linked parts of an asymmetric key. Many cryptographic toolkits contain methods such as RSA and ECC for generating these keys. To create an asymmetric key, you will need a public key and its corresponding private key. While the public key can be shared publicly, the private key must be kept secret.

You may use cryptographic libraries, like the cryptography in Python, for asymmetric key generation. Here is an example using RSA −

Example

The following codes generates an RSA key pair with a 512-bit key size for demonstration purposes. It then serializes the private and public keys into PEM format, which is commonly used for storing cryptographic keys in a readable format.

Finally, the code saves both keys to files and notifies the user of the successful operation.

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/bio.h>

#define RSA_KEY_BITS 2048
#define MAX_BUFFER_SIZE 8192

void print_openssl_error() {
   char err_buf[256];
   unsigned long err = ERR_get_error();
   ERR_error_string_n(err, err_buf, sizeof(err_buf));
   fprintf(stderr, "OpenSSL error: %s\n", err_buf);
}

void secure_memzero(void *buf, size_t len) {
   volatile unsigned char *p = (volatile unsigned char *)buf;
   while (len--) *p++ = 0;
}

void print_bio_contents(const char *filename, const char *label) {
   BIO *bio = BIO_new_file(filename, "r");
   if (!bio) {
      fprintf(stderr, "Failed to open %s for reading\n", filename);
      return;
   }

   char *buffer = malloc(MAX_BUFFER_SIZE);
   if (!buffer) {
      fprintf(stderr, "Failed to allocate memory\n");
      BIO_free(bio);
      return;
   }

   memset(buffer, 0, MAX_BUFFER_SIZE);
   int read_size = BIO_read(bio, buffer, MAX_BUFFER_SIZE - 1);
   if (read_size > 0) {
      buffer[read_size] = '\0';
      printf("%s:\n%s\n", label, buffer);
   }

   if (strstr(filename, "private")) {
      secure_memzero(buffer, MAX_BUFFER_SIZE);
   }

   free(buffer);
   BIO_free(bio);
}

int generate_asymmetric_keypair() {
   EVP_PKEY *pkey = NULL;
   EVP_PKEY_CTX *ctx = NULL;
   BIO *priv_bio = NULL;
   BIO *pub_bio = NULL;
   int ret = -1;

   // Initialize OpenSSL
   OpenSSL_add_all_algorithms();
   ERR_load_crypto_strings();

   // Create context and generate key
   ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
   if (!ctx) {
      fprintf(stderr, "Failed to create key context\n");
      print_openssl_error();
      goto cleanup;
   }

   if (EVP_PKEY_keygen_init(ctx) <= 0) {
      fprintf(stderr, "Failed to initialize key generation\n");
      print_openssl_error();
      goto cleanup;
   }

   if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, RSA_KEY_BITS) <= 0) {
      fprintf(stderr, "Failed to set key size\n");
      print_openssl_error();
      goto cleanup;
   }

   if (EVP_PKEY_keygen(ctx, &pkey) <= 0) {
      fprintf(stderr, "Failed to generate key\n");
      print_openssl_error();
      goto cleanup;
   }

   // Write private key using BIO
   priv_bio = BIO_new_file("private_key.pem", "w");
   if (!priv_bio) {
      fprintf(stderr, "Failed to create private key BIO\n");
      print_openssl_error();
      goto cleanup;
   }

   if (!PEM_write_bio_PrivateKey(priv_bio, pkey, NULL, NULL, 0, NULL, NULL)) {
      fprintf(stderr, "Failed to write private key\n");
      print_openssl_error();
      goto cleanup;
   }

   // Write public key using BIO
   pub_bio = BIO_new_file("public_key.pem", "w");
   if (!pub_bio) {
      fprintf(stderr, "Failed to create public key BIO\n");
      print_openssl_error();
      goto cleanup;
   }

   if (!PEM_write_bio_PUBKEY(pub_bio, pkey)) {
      fprintf(stderr, "Failed to write public key\n");
      print_openssl_error();
      goto cleanup;
   }

   // Close BIOs before reading
   BIO_free(priv_bio);
   BIO_free(pub_bio);
   priv_bio = pub_bio = NULL;

   // Print the keys
   print_bio_contents("private_key.pem", "Private Key");
   print_bio_contents("public_key.pem", "Public Key");

   ret = 0;  // Success

cleanup:
   // Clean up resources
   if (priv_bio) BIO_free(priv_bio);
   if (pub_bio) BIO_free(pub_bio);
   EVP_PKEY_free(pkey);
   EVP_PKEY_CTX_free(ctx);
   EVP_cleanup();
   ERR_free_strings();

   return ret;
}

int main() {
   if (generate_asymmetric_keypair() != 0) {
      fprintf(stderr, "Key generation failed\n");
      return 1;
   }
   return 0;
}

Output

The output obtained is as follows −

Private Key:
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDgWwije2eY4/P8
hj18dnBu0WALnCmGqdpU1YU6dmTZWOlOg4EPv10pourBEPy2bf3t67JEpRAN1L+n
hWOsGbHJb+Y4goO0UWthH/B9arbK06U/qHww/sPWpQzFIItANz6ygnACzzI/EaTK
VlT0Ep8DmdsBn/qvBWDVX8YUKxmlmyEuGhd4TpVnCitXzBhV5/Q9gQAz9OSonsIS
B+Dpq4kzRBBBdpwKrRiUSBeJsXwW3ejb8VketQnCpzHPM+klCe4Sljft64ku/omi
XQgmmaM0v1rM0kYhzcq9InSBQKAlMZyvZhj4QBTG8Fd8RHvc99gwSATzhphsm8Hl
JZL/YaQxAgMBAAECggEAMrVQoAap1RwcjsRWjFWGtv1avHUIy7eDMe5qpNqSk69t
WAIP/xus9laswYNR4ve8T3SYv7whA0dFJBtZelH6ZYGFotsY4n4Oi464/9fJRdGN
RXSS0U4bvF1ko/9lideSs60YnQHwpOGbgeH+ZIX668jv/4+FjN5l0wRJFFDjhJK9
kftlR57FGpLdYqr7MJO3aOXs0/5HUe3HBhBono4qpxUjqbStGuLtjfFow3GPXU9a
rm0gAVLIQwR4MjoW1jhRgWTUo6BBXDkG7QsA7CVm/7YDx+eJoNPWb4ftcYyvXn3n
uAKuXWAfJ/0bJJxcihqedLBIhOMWOUXgZXXjK2gaOQKBgQD1GFfUrphBU/ONxNCa
mJnFxx1Tgv8VTSKwsnHEP8Bsid07vIj+0gKzQG6DwTlGCkbpM+nb822btnysySEt
pn7AyaS0psj+74ZfS5Kxny/GsIWNgRO4T1n+py4JAPih3rOPwFPGJLswVUTkZXVc
IFXGVym3kszel9869yHTk/JvnQKBgQDqVndCEgfj52Xxno4ypSeJoHDmi+d8YSkK
51xFsYj+leSipODGwCcb2jTM6eFNSbt05+91YlP+ME8Rn61IJyI7gUMNUMfOXAOD
Yw29uuJqE7/u4Ke9geO9yV5sfsi3Wk1g+PNLa2z2wwPOGs0iRPTPQt348usDpdjD
mn232EJEpQKBgQCdU2btqrUpGg54riGJWvM6NTnp5Wh/7+eYrLLCWnnWMhjEw5zc
lUoObgmCoYF2KBqkjyJKgdOV5GnbL7AQcZNjhQwoufbDTlVezk/3nEs6qwzPbE+Q
O7906zNtrCXtIdr5J2efBOzzdYinY0kWPdtRWZn5sE25hJtSalhYS9uPMQKBgQCq
Av9U3PYCf7AzYuAxmCaeL9uZN+lDEM6RDZehLJOCeMc+xLYbG++DwoTKIeiGhTbO
MzNEi4j6gpvq4lj6XwHz/+zgrTm42oLmAKhIfVykrx1xtmWcFK9g0saBml4OwCIh
d5wznIWaZZPOJR2sfjDKae3XHo4owFsKVnxdNDWnzQKBgD9lxp57xCjOzHIlJYiE
3+ue3sy5zk9m2dmf8H7jtoylZi2heFSpV9b9IfdtjOJuXayz6Fgpz9MJMXYxAUeL
KCiYFkxl+L/r28FWLTQ5oQ+wAvpn1O19HzA0s0gK37L7mNQShBuKtb0O7I7QnlMs
3qPsp9TmsI+hWkiKptveaojh
-----END PRIVATE KEY-----

Public Key:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4FsIo3tnmOPz/IY9fHZw
btFgC5wphqnaVNWFOnZk2VjpToOBD79dKaLqwRD8tm397euyRKUQDdS/p4VjrBmx
yW/mOIKDtFFrYR/wfWq2ytOlP6h8MP7D1qUMxSCLQDc+soJwAs8yPxGkylZU9BKf
A5nbAZ/6rwVg1V/GFCsZpZshLhoXeE6VZworV8wYVef0PYEAM/TkqJ7CEgfg6auJ
M0QQQXacCq0YlEgXibF8Ft3o2/FZHrUJwqcxzzPpJQnuEpY37euJLv6Jol0IJpmj
NL9azNJGIc3KvSJ0gUCgJTGcr2YY+EAUxvBXfER73PfYMEgE84aYbJvB5SWS/2Gk
MQIDAQAB
-----END PUBLIC KEY-----
#include <iostream>
#include <string>
#include <memory>
#include <vector>
#include <fstream>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/bio.h>

class OpenSSLException : public std::runtime_error {
public:
   OpenSSLException(const std::string& message) : std::runtime_error(message) {
      char err_buf[256];
      unsigned long err = ERR_get_error();
      ERR_error_string_n(err, err_buf, sizeof(err_buf));
      what_message = message + ": " + err_buf;
   }
    
   const char* what() const noexcept override {
      return what_message.c_str();
   }

private:
   std::string what_message;
};

// Custom deleters for smart pointers
struct BIODeleter {
   void operator()(BIO* bio) { BIO_free(bio); }
};

struct EVP_PKEY_CTXDeleter {
   void operator()(EVP_PKEY_CTX* ctx) { EVP_PKEY_CTX_free(ctx); }
};

struct EVP_PKEYDeleter {
   void operator()(EVP_PKEY* key) { EVP_PKEY_free(key); }
};

class KeyPairGenerator {
public:
   static constexpr int RSA_KEY_BITS = 2048;
   static constexpr size_t MAX_BUFFER_SIZE = 8192;

   KeyPairGenerator() {
      OpenSSL_add_all_algorithms();
      ERR_load_crypto_strings();
   }

   ~KeyPairGenerator() {
      EVP_cleanup();
      ERR_free_strings();
   }

   void generateKeyPair() {
      generateKeys();
      writeKeys();
      printKeys();
   }

private:
   std::unique_ptr<EVP_PKEY, EVP_PKEYDeleter> pkey;

   void generateKeys() {
      std::unique_ptr<EVP_PKEY_CTX, EVP_PKEY_CTXDeleter> ctx(
         EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr));
        
      if (!ctx) {
         throw OpenSSLException("Failed to create key context");
      }

      if (EVP_PKEY_keygen_init(ctx.get()) <= 0) {
         throw OpenSSLException("Failed to initialize key generation");
      }

      if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx.get(), RSA_KEY_BITS) <= 0) {
         throw OpenSSLException("Failed to set key size");
      }

      EVP_PKEY* pkey_raw = nullptr;
      if (EVP_PKEY_keygen(ctx.get(), &pkey_raw) <= 0) {
         throw OpenSSLException("Failed to generate key");
      }
      pkey.reset(pkey_raw);
   }

   void writeKeys() {
      // Write private key
      std::unique_ptr<BIO, BIODeleter> priv_bio(BIO_new_file("private_key.pem", "w"));
      if (!priv_bio || !PEM_write_bio_PrivateKey(priv_bio.get(), pkey.get(), 
         nullptr, nullptr, 0, nullptr, nullptr)) {
         throw OpenSSLException("Failed to write private key");
      }

      // Write public key
      std::unique_ptr<BIO, BIODeleter> pub_bio(BIO_new_file("public_key.pem", "w"));
      if (!pub_bio || !PEM_write_bio_PUBKEY(pub_bio.get(), pkey.get())) {
         throw OpenSSLException("Failed to write public key");
      }
   }

   void printKeyFile(const std::string& filename, const std::string& label) {
      std::unique_ptr<BIO, BIODeleter> bio(BIO_new_file(filename.c_str(), "r"));
      if (!bio) {
         throw OpenSSLException("Failed to open " + filename + " for reading");
      }

      std::vector<char> buffer(MAX_BUFFER_SIZE);
      int read_size = BIO_read(bio.get(), buffer.data(), buffer.size() - 1);
      if (read_size > 0) {
         buffer[read_size] = '\0';
         std::cout << label << ":\n" << buffer.data() << std::endl;
      }

      if (filename.find("private") != std::string::npos) {
         std::fill(buffer.begin(), buffer.end(), 0);
      }
   }

   void printKeys() {
      try {
         printKeyFile("private_key.pem", "Private Key");
         printKeyFile("public_key.pem", "Public Key");
      } catch (const OpenSSLException& e) {
         std::cerr << "Error printing keys: " << e.what() << std::endl;
      }
   }
};

int main() {
   try {
      KeyPairGenerator generator;
      generator.generateKeyPair();
      return 0;
   } catch (const std::exception& e) {
      std::cerr << "Error: " << e.what() << std::endl;
      return 1;
   }
}

Output

The output produced is as follows −

Private Key:
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC41G/2hf3GwBWx
VDIgTltVlytZ8RPgiYAoKG9ibTZi1clnrcQjKz/nbO59hrTD5jFsKvGTlbtTRB7t
DsInOyJM65/PD6U1O6KejsQTxFx7HTA1GqBtESgwJoPW/JcDAIMLk3CkJh5dalP0
Lp61kVhEHLFopHdAw0Oxldv8VM0Em1unagAAI3AHY4f0iq1zS0Q/9zhreQHvklh+
NXar672ZLaOnIP0AP/HidCepbRPQPWX0kWgP6W66k63FCImm3qpJOEYWUl9RGDEt
1THfKY42XEfy6x8MAcL29/4aZ6ByA2dWBq3tDZZqvtvlvlgqr3N8GsOyd9U9b7P0
OIW3Hbh7AgMBAAECggEAA2nELLaN56OvBqH/wRbawLENIpji242UICm4Z6vYoOj3
LLPJ1TZPXgfAWofkhm+zzA82A8dWT4ifVGc9A48JwsOGrMpwHQzWo5a0Rpmkop4X
BEfL1PfHydrmk6ni68iQovLpe5jhjI0C76S5dRmbTxTOrphdvM/WxIjhr+uOnxLF
31CEffnrIlIlbw1U4OuPH8NdWdp95PGZOfzo0dkncvY7kDnXQTfAYClKn4L4WMV8
4lV+PWeJauzDJ4fv/Hxev6/vkeYsYdhpUDQoCEl6Av/9w82tNmm7kfk2Bf5/FEM9
JBW0GqDj5RSg1t+rWRiE9T+fGfT1VOgfiGibKUEKQQKBgQD2AQiotk7vpuFaiCb0
ItDtWYR2m9Oc+6W6U16RH1kWGIWovL7NfusQWTULqZLef/b/jFxrsE5p/e2yVCUA
PNOq3agIPjcoAGhE/hdv7oUncIdd0qnB4ev/8IWHBfjOH6E6DN0arifR8F+Y+KsH
HlLYvUUGQc1z/wFgedluInm9sQKBgQDAVw+7TKelexbln5EntEbdxnD6ffq01MZo
M/GaO9lUSO345wAruPy/NlKnKj6HJJXu5Lry83MNX8lNoF0n+LZfsOyzNyytGHn/
t1TjhETZ/h9o/MMNgs1MSFqGk9zQS3j/trSFtlaJ5y+/HKYlQv07FXbThz/LlZ8i
N1MdD2jH6wKBgBcFb78CGI76yfoD5clQ/MZJa0kCOiJltlOie6YPDfIwZ0msKBro
9qx3/KvTuafSx9WQWBHH1P68QaM/lprYFmLWDWSAFf9LUnaqZJ0X8CQJttFD5pj7
QG+aHZTOLUN02EyraYGWrKlL2lZhZvfqkYww4iW8wLJLOeDCZmOVHFlxAoGAWmMP
g4d8aSm1EuevwSbY/rOYuD6nqH8tVh7C9SYW9aLoIkX8MI/YRstygBg8Fio9Q2y9
5ho+ART4dsBbxsL8gW+VbIsLNbUA8AjpnZm0+XSQsjfGOf00GRsPX5rw8/njvNfR
cdzEQj4glAEUmwImGrP1iWZPto5zoBK7vjZVmU0CgYEAzKcgX4ZjzicAwHzBUze5
bMSUFnxlpmYqvNkSUM5iCIavgozN907FGkrUFuNj9Py5Jm41YD5YDM34+LGqzxyL
2kchI41S06Cr3FSW9wtjkWkB1o4NCrOlD5TaNC2kd+sJyBo2KzZcA7FevfzDtOgm
+/1et4M6c2x/w98nYlZvOtg=
-----END PRIVATE KEY-----

Public Key:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuNRv9oX9xsAVsVQyIE5b
VZcrWfET4ImAKChvYm02YtXJZ63EIys/52zufYa0w+YxbCrxk5W7U0Qe7Q7CJzsi
TOufzw+lNTuino7EE8Rcex0wNRqgbREoMCaD1vyXAwCDC5NwpCYeXWpT9C6etZFY
RByxaKR3QMNDsZXb/FTNBJtbp2oAACNwB2OH9Iqtc0tEP/c4a3kB75JYfjV2q+u9
mS2jpyD9AD/x4nQnqW0T0D1l9JFoD+luupOtxQiJpt6qSThGFlJfURgxLdUx3ymO
NlxH8usfDAHC9vf+GmegcgNnVgat7Q2War7b5b5YKq9zfBrDsnfVPW+z9DiFtx24
ewIDAQAB
-----END PUBLIC KEY-----

PS C:\Users\Tutorialspoint\Desktop\Compilers> g++ -o keypair keypair.cpp -std=c++17 -lssl -lcrypto
PS C:\Users\Tutorialspoint\Desktop\Compilers> ./keypair
Private Key:
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDK7l2j3PlmOIvQ
LGcv+0etxnqWhm4TAZ7lV0it7YqbJh/Yy7s7qWL4cHB87/0f+o5zztktgLj5uLCY
jv/B3ErI7f8tP9Agrtn2rMqTmTCD5zO4E7CX2gENNkSIp3yunxa7xqJYc1mfq5ey
D/G+Nt2BODo4KiTur+qGxzNBOFGnRFrIf3NAuMN9Z6lb5qvxuHAqq5IXMKpZDG8a
enW6SpDk2gJTJs+HA8+dJyRxyMY51iH4AMS6+G0wtatZL5iPr3cj7u0OBdLqgUR8
ydt4t9HsXqOqdy2XztBaWdCtOArvTUchUGFRH1LRB4NaIcp1pOsOwaxKsdQaBi2t
bo0xjPtBAgMBAAECggEAIpypaAuGlkLKxgTszKhFP4R84DOpjqBWI7PRd6juXSwR
fn6xPqnTcaBr70NXnx6zMVl0fWhZJG614C9zu/MA5miBf4xEyW5JSuOJ4cbdGYJT
te/VzPCoAULiSZSXlYkY7Yohooh6Htu7kelaSCE/goy+kVnO1s82ZyqOuW8LrkWS
kHl8tWbhJ/p9kebOhqCS8jXbtF1h92LYdJfM37/HBx27JgUEFy4Wp9hUzqkDkZct
mEmqXOkCEO5+Ak4lpMZ92XpkxZpUbBZiMUA3zeET+oe8088eY0HbFDQ6AXl97xaZ
OWUgkwwyt994iCh3pkqju2Dqe8FuQDFyNXyibRymKQKBgQDsfdxLPwKKTEON7pPZ
SFue3KDyqybc0kYDBZ6dx4dK22T5A8N9jCti/x+F+ZCYZHt96PNP38e2t0HTf4i7
8p2xPg4UwPhBdViL1ljZHAVK8KOBNeStjIEWyKL72feNNsNuJ7XKxFMC/n6Q+29l
c5E/zLZjmVHx8PXkZ3wGXZKTFwKBgQDbq8l3o9KQPwcflhSoH1RDEI3DJOzY0pAC
pybWWv+Ueqr822hm6G2RFDpa7nG/72ZLNfUS3iLbiA0g48VeWxuywKJFRPdaQQPv
HqsQmuEdDAs3E+F2UzXx3HuOSyIXMpg5Eo8jQbUMcVV/0mvcQ9haF6kJd7V9z9gH
hdMy1C67ZwKBgCnSoFDWVdarYg8JsC/u8fUIQ5Zm2jqXHTaPmduBW9XLMvIuzjW3
wjyBrct9tSqeKpC7z7vCcYlIo2WJ2l6Sq3ya4tacwcqhvAUO5SuQHwd/wwqow0ZF
4NZsqRYtF/BrTOiAMVAopB2VcECnlq20YG2OAHtgs/M7j+DSxEZD6hYFAoGBANcB
WAqatNBscDtxOLypFV8ix64V6R/7T+rY0cGChZ89RTiCQ7hdjEgwpUE1Gu7CkbvR
jxKtiy6WBkuHxDkrMXwO4YStEPEsq34S5Vo2TVmR3TRGaCnZHfahV+mZDj/oTGeo
C6N1f5AzKX0XZmzLlunvOIrEuUXv9cC/Mk0QssDHAoGAUZTaEyjrQMneFs4O0ffL
86vV6knx5jScIbVVLqKa2DAl3KAB7Xw8YRVSNIyNNUIhSIGOgqf17bmMv/2PaKvn
JNxOT/TP9gx+TWBCGfTpzqqQFlHYeFp8bcFxVPE8LgA+gvxwspXnDBcg31SIVpNl
/l/IM0g3cMov4G9o1hR5Y0s=
-----END PRIVATE KEY-----

Public Key:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyu5do9z5ZjiL0CxnL/tH
rcZ6loZuEwGe5VdIre2KmyYf2Mu7O6li+HBwfO/9H/qOc87ZLYC4+biwmI7/wdxK
yO3/LT/QIK7Z9qzKk5kwg+czuBOwl9oBDTZEiKd8rp8Wu8aiWHNZn6uXsg/xvjbd
gTg6OCok7q/qhsczQThRp0RayH9zQLjDfWepW+ar8bhwKquSFzCqWQxvGnp1ukqQ
5NoCUybPhwPPnSckccjGOdYh+ADEuvhtMLWrWS+Yj693I+7tDgXS6oFEfMnbeLfR
7F6jqnctl87QWlnQrTgK701HIVBhUR9S0QeDWiHKdaTrDsGsSrHUGgYtrW6NMYz7
QQIDAQAB
-----END PUBLIC KEY-----
import java.security.*;
import java.util.Base64;
import javax.crypto.Cipher;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

public class RSAKeyPairGenerator {
   public static void main(String[] args) throws Exception {
      KeyPair keyPair = generateAsymmetricKeyPair();
      String privateKeyPEM = convertToPEM(keyPair.getPrivate().getEncoded(), "PRIVATE KEY");
      String publicKeyPEM = convertToPEM(keyPair.getPublic().getEncoded(), "PUBLIC KEY");
      
      System.out.println("Private Key:\n" + privateKeyPEM);
      System.out.println("Public Key:\n" + publicKeyPEM);
   }
   
   public static KeyPair generateAsymmetricKeyPair() throws NoSuchAlgorithmException {
      KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
      keyPairGenerator.initialize(512); // 512-bit key size 
      return keyPairGenerator.generateKeyPair();
   }
   
   public static String convertToPEM(byte[] keyBytes, String keyType) {
      String base64Encoded = Base64.getMimeEncoder(64, new byte[]{'\n'}).encodeToString(keyBytes);
      return "-----BEGIN " + keyType + "-----\n" + base64Encoded + "\n-----END " + keyType + "-----\n";
   }
}

Output

The output obtained is as shown below −

Private Key:
-----BEGIN PRIVATE KEY-----
MIIBVgIBADANBgkqhkiG9w0BAQEFAASCAUAwggE8AgEAAkEAwm2Zj2lOe6kg6TDH
sjw2O67HC8YcPvmA5MAtRNMCkye+KvyYWDQYv8d6Ko6OM9DIJvd0SOVemEOM8C8L
yg6NBwIDAQABAkAptKzd8G7fY9Ylb0tG1lej0cfspKBmecrGRtrvCnxg6CMokshf
AIwWWaadeuHuLXPjE3xJhbsivxzZDEjz1YDhAiEAxlqpH44yGlcHmp6WqU6e+w5s
LHLhHu+brcPGVgtQf+8CIQD67tj466TGFjBb1FhYsX0UzF0cZ4QumvUEkw7S88Ms
aQIhAIWEs4FVQ26tlKXFCN+Q171hWPmWnuknGyEdvp1e4mIrAiEAg1xt8UFKrPgI
sMnkxemEVVL2m1wFcnBkO9TQOdaqIaECIQCRfPEWIBp0AiQxhKoiLmBNjy9OgQcM
TIC7g7QKhqF32A==
-----END PRIVATE KEY-----

Public Key:
-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAMJtmY9pTnupIOkwx7I8NjuuxwvGHD75
gOTALUTTApMnvir8mFg0GL/HeiqOjjPQyCb3dEjlXphDjPAvC8oOjQcCAwEAAQ==
-----END PUBLIC KEY-----
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import serialization

def generate_asymmetric_keypair():
   # generate an RSA key pair
   private_key = rsa.generate_private_key(
      public_exponent=65537,
      key_size=512,
      backend=default_backend()
   )
   # extract the public key
   public_key = private_key.public_key()
   # change keys to PEM format.
   private_key_pem = private_key.private_bytes(
      encoding=serialization.Encoding.PEM,
      format=serialization.PrivateFormat.PKCS8,
      encryption_algorithm=serialization.NoEncryption()
   )
   public_key_pem = public_key.public_bytes(
      encoding=serialization.Encoding.PEM,
      format=serialization.PublicFormat.SubjectPublicKeyInfo
   )
   return private_key_pem, public_key_pem

# generate an RSA key pair
private_key, public_key = generate_asymmetric_keypair()
print("Private Key:\n", private_key.decode())
print("Public Key:\n", public_key.decode())

Output

Following is the output of the above code −

Private Key:
 -----BEGIN PRIVATE KEY-----
MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEAnZDNW75C+UPNT/71
vXhuH+kbKTJSqhhmOgvG4wT3ihy7jqtPsQyiDt6bzP/8Tc9PSueSGT+HNSwR2APZ
uXiIgQIDAQABAkAheLtHO/m6Pf8FeWH2p/is6rYMYFZTL++3cP0FCO8U9YRAzDcA
LsOA3jBx1AM7CwkcTIv/SEf0NHAtauG2NEOJAiEAzTZHCOwPzRZUbyNLBiPlyk7q
Z5P7R6N8dGHTKw6LLt8CIQDEj8Srv/2JVCe8pFRB1HnTsqnJ6YzusGMTlwMPE0MU
nwIgdO4LleLksgiaPeWPV0VXJ2rGGBTzJoPaY3pmV+9mkWMCIEf2wvCGmBKBRxMf
ruFzIy9IiDUuVrTEy2FOtoX8bWDNAiBznEC37fHo8LgEd60xpCB5m/6xiHS7NYru
0DM7ARSidg==
-----END PRIVATE KEY-----

Public Key:
 -----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJ2QzVu+QvlDzU/+9b14bh/pGykyUqoY
ZjoLxuME94ocu46rT7EMog7em8z//E3PT0rnkhk/hzUsEdgD2bl4iIECAwEAAQ==
-----END PUBLIC KEY-----

Considerations for Key Length

There are certain Considerations to be followed for generating Symmetric and Asymmetric Keys −

  • The encryption strength is determined by the key length.

  • Longer keys provide greater security, but they may need more computational resources.

  • Symmetric keys often have lengths of 128 bits or more.

  • Asymmetric keys in RSA typically have a length of 2048 bits or more.

Testing and Validating Keys

After securely creating the keys we must test and validate it in your cryptographic system to make sure that they are working as expected.

Then, validate the keys' security by evaluating how vulnerable they are to known attacks and errors.

Summary

Overall, key generation is essential for preserving confidentiality, integrity, and validity of data in cryptographic systems. To minimize the risk of cryptographic attacks, carefully analyze randomization, algorithm selection, key size, and secure storage methods.

Advertisements