Skip to content

Instantly share code, notes, and snippets.

@bricef
Last active May 11, 2024 21:15
Show Gist options
  • Save bricef/2436364 to your computer and use it in GitHub Desktop.
Save bricef/2436364 to your computer and use it in GitHub Desktop.
A simple example of using AES encryption in Java and C.

README

DO NOT USE THIS CODE IN PRODUCTION

This is an educational example of how to use the Java and C AES libraries originally from a Stackoverflow Answer. This code is not safe and it is not an example of how to securely use AES.

Many additional factors will need to be considered when buidling a secure system that uses AES, for example: How to properly use IVs; Block cipher modes and their properties; Secure key generation; Key distribution; message and author authentication; and many more factors besides.

At a minimum, you'll want to go through and make sure you understand the Cryptography Engineering Book, and are aware of any current security issues reported about the library you are using.

If you don't already

  • Know how to use and import a C library
  • Understand what IVs are and how they should be used
  • Understand the difference between block size and key size
  • Know that Libmcrypt is deprecated and why you still want to use it

Do not use this code.

Libmcrypt is deprecated

The library used in the C example, Libmcrypt, is deprecated. It'll work, but for most use cases, you'll want to use a more modern cryptographic library. Current recommeded best practice would point to NaCl and its close cousin Libsodium Which have been extensively tested, audited and only allow current best practice algorithms and methods.

Issues with the code

As commented below there are a couple of issues with the code. It was written to be a quick example, not a reference and as such handles its data badly.

@rwst comments:

[...] the buffer, when decrypted, certainly won't have a 0 byte at the end, so printing it as is, even if it is printable, will get another unexpected result.

You should know what this means and how to handle the case where the decrypted data doesn't include a terminating null character.

You should be able to realise that the C code currently encrypts memory outside of the plaintext string since the buffer length is greater than the string length (and why the Java string is padded). If this isn't clear to you, don't use this code.

Common issues

AES.c:9:20: fatal error: mcrypt.h: No such file or directory

If you are getting this error and do not know what it means or how to resolve it, STOP. YOU DO NOT KNOW ENOUGH TO BE WRITING SECURITY SOFTWARE. I will not help you to resolve this issue, to discourage you from continuing with this code sample.

I'm sorry to be so blunt, and don't want to discourage you from learning C programming or software security, which are both very rewarding, but you should start your journey with a simpler example. There are many great resources for you. I'd recommend starting with The C Programming Language. It's old now, and has some questionable examples and practices, but it's still a great start. There is also a communtiy list of resources on Stackoverflow to get you started.

Recommended resources

If you want to learn more about how to use cryptography correctly, a good start is Cryptography Engineering. You should also use modern, independently audited and tested libraries like NaCl or Libsodium.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
* MCrypt API available online:
* http://linux.die.net/man/3/mcrypt
*/
#include <mcrypt.h>
#include <math.h>
#include <stdint.h>
#include <stdlib.h>
int encrypt(
void* buffer,
int buffer_len, /* Because the plaintext could include null bytes*/
char* IV,
char* key,
int key_len
){
MCRYPT td = mcrypt_module_open("rijndael-128", NULL, "cbc", NULL);
int blocksize = mcrypt_enc_get_block_size(td);
if( buffer_len % blocksize != 0 ){return 1;}
mcrypt_generic_init(td, key, key_len, IV);
mcrypt_generic(td, buffer, buffer_len);
mcrypt_generic_deinit (td);
mcrypt_module_close(td);
return 0;
}
int decrypt(
void* buffer,
int buffer_len,
char* IV,
char* key,
int key_len
){
MCRYPT td = mcrypt_module_open("rijndael-128", NULL, "cbc", NULL);
int blocksize = mcrypt_enc_get_block_size(td);
if( buffer_len % blocksize != 0 ){return 1;}
mcrypt_generic_init(td, key, key_len, IV);
mdecrypt_generic(td, buffer, buffer_len);
mcrypt_generic_deinit (td);
mcrypt_module_close(td);
return 0;
}
void display(char* ciphertext, int len){
int v;
for (v=0; v<len; v++){
printf("%d ", ciphertext[v]);
}
printf("\n");
}
int main()
{
MCRYPT td, td2;
char* plaintext = "test text 123";
char* IV = "AAAAAAAAAAAAAAAA";
char* key = "0123456789abcdef";
int keysize = 16; /* 128 bits */
char* buffer;
int buffer_len = 16;
buffer = calloc(1, buffer_len);
strncpy(buffer, plaintext, buffer_len);
printf("==C==\n");
printf("plain: %s\n", plaintext);
encrypt(buffer, buffer_len, IV, key, keysize);
printf("cipher: "); display(buffer , buffer_len);
decrypt(buffer, buffer_len, IV, key, keysize);
printf("decrypt: %s\n", buffer);
return 0;
}
import java.security.MessageDigest;
import java.util.Arrays;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class AES {
static String IV = "AAAAAAAAAAAAAAAA";
static String plaintext = "test text 123\u0000\u0000\u0000"; /*Note null padding*/
static String encryptionKey = "0123456789abcdef";
public static void main(String [] args) {
try {
System.out.println("==Java==");
System.out.println("plain: " + plaintext);
byte[] cipher = encrypt(plaintext, encryptionKey);
System.out.print("cipher: ");
for (int i=0; i<cipher.length; i++)
System.out.print(new Integer(cipher[i])+" ");
System.out.println("");
String decrypted = decrypt(cipher, encryptionKey);
System.out.println("decrypt: " + decrypted);
} catch (Exception e) {
e.printStackTrace();
}
}
public static byte[] encrypt(String plainText, String encryptionKey) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding", "SunJCE");
SecretKeySpec key = new SecretKeySpec(encryptionKey.getBytes("UTF-8"), "AES");
cipher.init(Cipher.ENCRYPT_MODE, key,new IvParameterSpec(IV.getBytes("UTF-8")));
return cipher.doFinal(plainText.getBytes("UTF-8"));
}
public static String decrypt(byte[] cipherText, String encryptionKey) throws Exception{
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding", "SunJCE");
SecretKeySpec key = new SecretKeySpec(encryptionKey.getBytes("UTF-8"), "AES");
cipher.init(Cipher.DECRYPT_MODE, key,new IvParameterSpec(IV.getBytes("UTF-8")));
return new String(cipher.doFinal(cipherText),"UTF-8");
}
}
@adityashah1603
Copy link

i am getting undefined references for some of the predefined function from the mcrypt file, i checked the names and they match, any fix? if yes it would be highly appreciated to be answered ASAP.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment