Cryptography is broadly divided into two levels. One with safe cryptographic recipes that require little to no configuration choices. These are safe and easy to use and don’t require developers to make many decisions. The other level is low-level cryptographic primitives. These are often dangerous and can be used incorrectly. They require making decisions and having an in-depth knowledge of the cryptographic concepts at work. Because of the potential danger in working at this level, this is referred to as the “hazardous materials” or “hazmat” layer. These live in cryptography.

**Keys:**

**Symmetric Key:**The same key is used for both encryption and decryption.**Asymmetric Key:**Two different keys are used – a public key for encryption and a private key for decryption.

### (Fernet ) Symmetric Encryption:

Fernet guarantees that a message encrypted using it cannot be manipulated or read without the key. Fernet is an implementation of symmetric (also known as “secret key”) authenticated cryptography. Fernet also has support for implementing key rotation via MultiFernet.

class cryptography.fernet.Fernet(key).

This class provides both encryption and decryption facilities.

**Ex:**

>>> from cryptography.fernet import Fernet

>>> key = Fernet.generate_key()

>>> f = Fernet(key)

>>> token = f.encrypt(b”my deep dark secret”)

>>> f.decrypt(token);

**Output**: b’my deep dark secret’

**Parameters:**

**key (bytes or str)** – A URL- “safe base64-encoded 32-byte key”.

This must be kept secret. Anyone with this key is able to create and read messages. classmethod generate_key() Generates a fresh fernet key. Keep this some place safe! If you lose it you’ll no longer be able to decrypt messages; if anyone else gains access to it, they’ll be able to decrypt all of your messages, and they’ll also be able forge arbitrary messages that will be authenticated and decrypted. encrypt(data) Encrypts data passed. The result of this encryption is known as a “Fernet token” and has strong privacy and authenticity guarantees.

**Classmethod** – **generate_key() **:

Generates a fresh fernet key. Keep this some place safe! If you lose it you’ll no longer be able to decrypt messages; if anyone else gains access to it, they’ll be able to decrypt all of your messages, and they’ll also be able forge arbitrary messages that will be authenticated and decrypted.

**Encrypt(data):**

Encrypts data passed. The result of this encryption is known as a “Fernet token” and has strong privacy and authenticity guarantees.

**decrypt (token, ttl=None):**

Decrypts a Fernet token. If successfully decrypted you will receive the original plaintext as the result, otherwise an exception will be raised. It is safe to use this data immediately as Fernet verifies that the data has not been tampered with prior to returning it.

**Parameters:**

• token (bytes or str) – The Fernet token. This is the result of calling encrypt().

• ttl (int) – Optionally, the number of seconds old a message may be for it to be valid. If the message is older than ttl seconds (from the time it was originally created) an exception will be raised. If ttl is not provided (or is None), the age of the message is not considered.

**Returns bytes:** The original plaintext.

**Raises:**

• cryptography.fernet.InvalidToken – If the token is in any way invalid, this exception is raised. A token may be invalid for a number of reasons: it is older than the ttl, it is malformed, or it does not have a valid signature.

• TypeError – This exception is raised if token is not bytes or str.

### Algorithms:

**Symmetric Algorithms:****AES (Advanced Encryption Standard):**Widely used, secure, and efficient.

**DES (Data Encryption Standard):**Outdated and less secure, replaced by AES.

**Asymmetric Algorithms:****RSA (Rivest-Shamir-Adleman):**Commonly used for secure data transmission.

**ECC (Elliptic Curve Cryptography):**More efficient and secure compared to RSA.

**Hash Functions:****SHA-256 (Secure Hash Algorithm):**Produces a 256-bit hash value, widely used for integrity checks.

**MD5 (Message Digest Algorithm 5):**Produces a 128-bit hash value, considered insecure for most applications.

**Symmetric Encryption with AES****:**

import javax.crypto.Cipher;

import javax.crypto.KeyGenerator;

import javax.crypto.SecretKey;

import javax.crypto.spec.IvParameterSpec;

import java.security.SecureRandom;

import java.util.Base64;

public class **AESEncryptionExample **{

public static void main(String[] args) throws Exception {

// Generate a random key and IV (Initialization Vector)

KeyGenerator keyGen = KeyGenerator.getInstance(“AES”);

keyGen.init(128); // 128 bits key size

SecretKey secretKey = keyGen.generateKey();

byte[] iv = new byte[16];

SecureRandom random = new SecureRandom();

random.nextBytes(iv);

IvParameterSpec ivSpec = new IvParameterSpec(iv);

// The plaintext message to be encrypted

String plaintext = “This is a secret message”;

// Encrypt the plaintext

String ciphertext = encrypt(plaintext, secretKey, ivSpec);

System.out.println(“Ciphertext: ” + ciphertext);

// Decrypt the ciphertext

String decryptedText = decrypt(ciphertext, secretKey, ivSpec);

System.out.println(“Decrypted text: ” + decryptedText);

}

public static String **encrypt**(String plaintext, SecretKey key, IvParameterSpec iv) throws Exception {

Cipher cipher = Cipher.getInstance(“AES/CBC/PKCS5Padding”);

cipher.init(Cipher.ENCRYPT_MODE, key, iv);

byte[] encryptedBytes = cipher.doFinal(plaintext.getBytes());

return Base64.getEncoder().encodeToString(encryptedBytes);

}

public static String **decrypt**(String ciphertext, SecretKey key, IvParameterSpec iv) throws Exception {

Cipher cipher = Cipher.getInstance(“AES/CBC/PKCS5Padding”);

cipher.init(Cipher.DECRYPT_MODE, key, iv);

byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(ciphertext));

return new String(decryptedBytes);

}

}

**Asymmetric algorithms:**

Asymmetric cryptography is a branch of cryptography where a secret key can be divided into two parts, a public key and a private key. The public key can be given to anyone, trusted or not, while the private key must be kept secret (just like the key in symmetric cryptography). Asymmetric cryptography has two primary use cases: authentication and confidentiality. Using asymmetric cryptography, messages can be signed with a private key, and then anyone with the public key is able to verify that the message was created by someone possessing the corresponding private key. This can be combined with a proof of identity system to know what entity (person or group) owns that private key, providing authentication. Encryption with asymmetric cryptography works in a slightly different way from symmetric encryption. Someone with the public key can encrypt a message, providing confidentiality, and then only the person in possession of the private key is able to decrypt it.

**Asymmetric Encryption with RSA (in Java):**

import java.security.*;

import java.util.Base64;

import javax.crypto.Cipher;

public class **RSAEncryptionExample **{

public static void main(String[] args) throws Exception {

// Generate RSA key pair

KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(“RSA”);

keyPairGen.initialize(2048); // Key size

KeyPair keyPair = keyPairGen.generateKeyPair();

PublicKey publicKey = keyPair.getPublic();

PrivateKey privateKey = keyPair.getPrivate();

// The plaintext message to be encrypted

String plaintext = “This is a secret message”;

// Encrypt the plaintext using the public key

String ciphertext = encrypt(plaintext, publicKey);

System.out.println(“Ciphertext: ” + ciphertext);

// Decrypt the ciphertext using the private key

String decryptedText = decrypt(ciphertext, privateKey);

System.out.println(“Decrypted text: ” + decryptedText);

}

**Encrypt:**

public static String **encrypt**(String plaintext, PublicKey publicKey) throws Exception {

Cipher cipher = Cipher.getInstance(“RSA”);

cipher.init(Cipher.ENCRYPT_MODE, publicKey);

byte[] encryptedBytes = cipher.doFinal(plaintext.getBytes());

return Base64.getEncoder().encodeToString(encryptedBytes);

}

**Decrypt:**

public static String **decrypt**(String ciphertext, PrivateKey privateKey) throws Exception {

Cipher cipher = Cipher.getInstance(“RSA”);

cipher.init(Cipher.DECRYPT_MODE, privateKey);

byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(ciphertext));

return new String(decryptedBytes);

}

}

**Symmetric vs. Asymmetric Cryptography**

There are two major types of encryption: *symmetric* (also known as *secret key*), and *asymmetric* (or *public key cryptography*). In symmetric cryptography, the same secret key to both encrypt and decrypt the data. Keeping the key private is critical to keeping the data confidential. On the other hand, asymmetric cryptography uses a public/private key pair to encrypt data. Data encrypted with one key is decrypted with the other. A user first generates a public/private key pair, and then publishes the public key in a trusted database that anyone can access. A user who wishes to communicate securely with that user encrypts the data using the retrieved public key. Only the holder of the private key will be able to decrypt. Keeping the private key confidential is critical to this scheme.

Asymmetric algorithms (such as RSA) are generally much slower than symmetric ones. These algorithms are not designed for efficiently protecting large amounts of data. In practice, asymmetric algorithms are used to exchange smaller secret keys which are used to initialize symmetric algorithms.

### Digital Signatures:

- Used to verify the authenticity and integrity of a message.
- Created using a private key and verified with the corresponding public key.

### Certificates and Public Key Infrastructure (PKI):

**Certificates:**Digital documents that bind a public key to an entity’s identity, issued by a Certificate Authority (CA).**PKI:**A framework for managing public-key encryption, including the issuance, renewal, and revocation of certificates.