Computer scienceProgramming languagesKotlinAdditional instrumentsCryptography and encoding

Symmetric Encryption

5 minutes read

In today's interconnected world, the security of your communications is of utmost importance. Whether it's personal conversations, financial transactions, or sensitive data transfers, ensuring the confidentiality and integrity of information is crucial. One of the fundamental aspects of communication security lies in the use of encryption, which protects data from unauthorized access. In this topic, you will explore the significance of communication security. You will focus on the advantages of symmetric encryption, specifically highlighting the Advanced Encryption Standard (AES) algorithm. Lastly, you will discuss the security libraries available in the Java Virtual Machine (JVM) ecosystem.

Information Security and Encryption

Communication security plays a vital role in safeguarding sensitive information from unauthorized access, interception, and tampering. It ensures that only authorized parties can access and understand the data being transmitted. Without proper security measures, sensitive information can be compromised, leading to privacy breaches, financial losses, and reputational damage. By employing encryption techniques, you can protect your communications and maintain the confidentiality, integrity, and authenticity of the data.

To protect your information, you can use encryption techniques. Here are two techniques to note:

  • Asymmetric encryption: Also known as public-key encryption, asymmetric encryption involves the use of two different keys: a public key and a private key. The public key is freely distributed, while the private key is kept secret. The sender encrypts the data using the recipient's public key, and the recipient decrypts it using their private key. Asymmetric encryption provides a secure method for key exchange and digital signatures, but it is computationally more expensive than symmetric encryption.
  • Symmetric encryption: Also known as secret-key encryption, symmetric encryption employs a single key for both encryption and decryption. The same key is used by both the sender and the recipient, making it faster and more efficient than asymmetric encryption. However, the key exchange process in symmetric encryption requires a secure channel to prevent unauthorized access.

Symmetric Encryption with AES

As we have said before, in symmetric encryption, we use the same key to encrypt and decrypt the content. This offers us a series of advantages compared to asymmetric encryption:

  1. Efficiency: Symmetric encryption algorithms are computationally faster and require fewer resources than asymmetric algorithms.
  2. Key Management: Symmetric encryption requires the management of a single key, simplifying the key distribution process.
  3. Performance: Symmetric encryption is ideal for encrypting large amounts of data, making it suitable for securing files and data streams.

But it is essential to acknowledge some potential weaknesses:

  1. Key Distribution: Securely sharing the encryption key between the sender and recipient can be challenging.
  2. Key Management: Safeguarding and securely storing the encryption keys is crucial.
  3. Lack of Forward Secrecy: Compromising the encryption key compromises past and future communications.
  4. Limited Scalability: Establishing secure communication between multiple parties requires unique encryption keys for each pair.
  5. Vulnerability to Key Attacks: Brute-force attacks and other techniques can potentially compromise the security of AES-encrypted data.
  6. Side-Channel Attacks: AES can be vulnerable to attacks that exploit leaked information during encryption or decryption.

One widely used symmetric encryption algorithm is the Advanced Encryption Standard (AES). AES, also known by its original name, Rijndael, is a symmetric block cipher that operates on fixed-size blocks of data. It supports key sizes of 128, 192, and 256 bits, providing a high level of security. AES is included in the ISO/IEC 18033-3 standard and is available in many different encryption packages and languages.

Some characteristics of AES include:

  1. Security: AES is considered highly secure and has been adopted as the standard encryption algorithm by the U.S. government.
  2. Speed: AES is optimized for efficient implementation on various platforms, ensuring fast encryption and decryption operations.
  3. Versatility: AES can be used for a wide range of applications, including securing data at rest, data in transit, and wireless communications.

AES in Kotlin

The Java Virtual Machine ecosystem provides robust security libraries to facilitate secure communications. The java.security package in Java and the javax.crypto package in Java offer a wide range of cryptographic functionalities, including encryption, decryption, digital signatures, and key management. These libraries provide developers with the necessary tools to implement secure communication protocols and protect sensitive data.

In this example, we will show how to encrypt and decrypt a string.

import javax.crypto.Cipher
import javax.crypto.spec.SecretKeySpec
import java.util.Base64

fun encryptText(plainText: String, secretKey: String): String {
    val cipher = Cipher.getInstance("AES/ECB/PKCS5Padding")
    val key = SecretKeySpec(secretKey.toByteArray(), "AES")
    cipher.init(Cipher.ENCRYPT_MODE, key)
    val encryptedBytes = cipher.doFinal(plainText.toByteArray())
    return Base64.getEncoder().encodeToString(encryptedBytes)
}

fun decryptText(encryptedText: String, secretKey: String): String {
    val cipher = Cipher.getInstance("AES/ECB/PKCS5Padding")
    val key = SecretKeySpec(secretKey.toByteArray(), "AES")
    cipher.init(Cipher.DECRYPT_MODE, key)
    val encryptedBytes = Base64.getDecoder().decode(encryptedText)
    val decryptedBytes = cipher.doFinal(encryptedBytes)
    return String(decryptedBytes)
}

// Example usage
fun main() {
    val secretKey = "ThisIsASecretKey"
    val originalText = "Hello, World!"

    val encryptedText = encryptText(originalText, secretKey)
    println("Encrypted Text: $encryptedText")

    val decryptedText = decryptText(encryptedText, secretKey)
    println("Decrypted Text: $decryptedText")
}
Encrypted Text: "sGcPScqj8Z6Y9c3thb0MZg==" 
Decrypted Text: "Hello, World!"

The encryptText function takes a plain text string and a secret key as input parameters, returning the encrypted text as a Base64-encoded string.

The function operates as follows:

  • It creates a Cipher instance using the AES algorithm with ECB mode and PKCS5Padding padding.
  • It creates a SecretKeySpec object from the provided secret key.
  • It initializes the cipher with the encryption mode and the secret key.
  • It encrypts the plain text by calling doFinal on the cipher object, passing the plain text as a byte array.
  • The encrypted bytes are then encoded to Base64 using Base64.getEncoder().encodeToString(), and returned as the encrypted text. This step isn't mandatory, but we include it to demonstrate how to display the encrypted value through the console. The string provides an appropriate text encoding of this encrypted binary value.

The decryptText function takes an encrypted text string and a secret key as input parameters, returning the decrypted text.

This function operates as follows:

  • It creates a Cipher instance using the AES algorithm with ECB mode and PKCS5Padding padding.
  • It creates a SecretKeySpec object from the provided secret key.
  • It initializes the cipher with the decryption mode and the secret key.
  • It decodes the Base64-encoded encrypted text using Base64.getDecoder().decode(). Remember, we use Base64 to make the process symmetrical. If we used Base64 to obtain the string, we must now get its binary value to decrypt it.
  • It decrypts the encrypted bytes by calling doFinal on the cipher object, passing the encrypted bytes.
  • The decrypted bytes are converted to a string using the `String` constructor and returned as the decrypted text.

The following example illustrates how to use AES to encrypt and decrypt a file.

import javax.crypto.Cipher
import javax.crypto.spec.SecretKeySpec
import java.nio.file.Files
import java.nio.file.Paths
import java.nio.file.StandardOpenOption

fun encryptFile(inputFilePath: String, outputFilePath: String, secretKey: String) {
    val cipher = Cipher.getInstance("AES/ECB/PKCS5Padding")
    val key = SecretKeySpec(secretKey.toByteArray(), "AES")
    cipher.init(Cipher.ENCRYPT_MODE, key)

    val inputFileBytes = Files.readAllBytes(Paths.get(inputFilePath))
    val encryptedBytes = cipher.doFinal(inputFileBytes)

    Files.write(Paths.get(outputFilePath), encryptedBytes, StandardOpenOption.CREATE)
}

fun decryptFile(inputFilePath: String, outputFilePath: String, secretKey: String) {
    val cipher = Cipher.getInstance("AES/ECB/PKCS5Padding")
    val key = SecretKeySpec(secretKey.toByteArray(), "AES")
    cipher.init(Cipher.DECRYPT_MODE, key)

    val encryptedBytes = Files.readAllBytes(Paths.get(inputFilePath))
    val decryptedBytes = cipher.doFinal(encryptedBytes)

    Files.write(Paths.get(outputFilePath), decryptedBytes, StandardOpenOption.CREATE)
}

fun main() {
    val inputFilePath = "input.txt"
    val encryptedFilePath = "encrypted.bin"
    val decryptedFilePath = "decrypted.txt"
    val secretKey = "ThisIsASecretKey"

    // Encrypt the file
    encryptFile(inputFilePath, encryptedFilePath, secretKey)
    println("File encrypted successfully.")

    // Decrypt the file
    decryptFile(encryptedFilePath, decryptedFilePath, secretKey)
    println("File decrypted successfully.")
}

Explanation of the Encryption Function:

  1. Import the necessary classes for encryption and file operations.
  2. Create an instance of Cipher, using the AES algorithm with ECB mode and PKCS5Padding padding.
  3. Create a SecretKeySpec object from the provided secret key.
  4. Initialize the cipher with the encryption mode and the secret key.
  5. Read all the bytes from the input file using Files.readAllBytes().
  6. Encrypt the input file bytes by calling doFinal() on the Cipher object.
  7. Write the encrypted bytes to the output file using Files.write(). Specify the output file path and use the StandardOpenOption.CREATE option to create the file if it doesn't exist.

Explanation of the Decryption Function:

  1. Import the necessary classes for decryption and file operations.
  2. Create an instance of Cipher, using the AES algorithm with ECB mode and PKCS5Padding padding.
  3. Create a SecretKeySpec object from the provided secret key.
  4. Initialize the cipher with the decryption mode and the secret key.
  5. Read all the bytes from the encrypted input file using Files.readAllBytes().
  6. Decrypt the encrypted bytes by calling doFinal() on the Cipher object.
  7. Write the decrypted bytes to the output file using Files.write(). Specify the output file path and use the StandardOpenOption.CREATE option to create the file if it doesn't exist.

Conclusion

The security of communications is paramount in the contemporary digital landscape. Encryption, utilizing either asymmetric or symmetric algorithms, provides a vital layer of protection for sensitive information. Symmetric encryption, exemplified by AES, offers advantages in terms of efficiency, key management, and performance. The JVM ecosystem, through libraries such as java.security and javax.crypto, equips developers with powerful tools to implement secure communication protocols in Kotlin. By incorporating encryption techniques and leveraging these libraries, we can safeguard the confidentiality and integrity of our communications, thus mitigating the risks associated with unauthorized access and data breaches. It's time to apply your knowledge with some practical tasks. Are you ready?

4 learners liked this piece of theory. 0 didn't like it. What about you?
Report a typo