0

I need to port application from Java to C++. I'm stuck on problem with AES CTR 128. In Java and C it has different encryption result. So my Java code.

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


class HelloWorld {
    public static void main(String[] args) {
        try 
        {

            byte[] keyBytes = Base64.getDecoder().decode("5gYDRl00XcjqlcC5okdBSfDx46HIGZBMAvMiibVYixc=");
            byte[] ivBytes = Base64.getDecoder().decode("AAAAAAAAAAAAAAAAAAAAAA==");

            SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
            IvParameterSpec iv = new IvParameterSpec(ivBytes);

            Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
            cipher.init(Cipher.ENCRYPT_MODE, key, iv);
            String encrypted = Base64.getEncoder().encodeToString(cipher.doFinal("This is a plaintext message.".getBytes()));
            System.out.println(encrypted); // print: sTBJYaaGNTxCErAXbP6eXnU59Yyn1UJAp7MGQw==

        } catch (Exception e) {}
        return;
    }
}

My C code. I use the same algorythm, plain text, key and iv. But get another cipher text result.

#include <openssl/conf.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>
#include <openssl/evp.h>
#include <stdio.h>
#include <string.h>

char *base64encode (const void *b64_encode_this, int encode_this_many_bytes)
{
    BIO *b64_bio, *mem_bio;      //Declares two OpenSSL BIOs: a base64 filter and a memory BIO.
    BUF_MEM *mem_bio_mem_ptr;    //Pointer to a "memory BIO" structure holding our base64 data.
    b64_bio = BIO_new(BIO_f_base64());                      //Initialize our base64 filter BIO.
    mem_bio = BIO_new(BIO_s_mem());                           //Initialize our memory sink BIO.
    BIO_push(b64_bio, mem_bio);            //Link the BIOs by creating a filter-sink BIO chain.
    BIO_set_flags(b64_bio, BIO_FLAGS_BASE64_NO_NL);  //No newlines every 64 characters or less.
    BIO_write(b64_bio, b64_encode_this, encode_this_many_bytes); //Records base64 encoded data.
    BIO_flush(b64_bio);   //Flush data.  Necessary for b64 encoding, because of pad characters.
    BIO_get_mem_ptr(mem_bio, &mem_bio_mem_ptr);  //Store address of mem_bio's memory structure.
    BIO_set_close(mem_bio, BIO_NOCLOSE);   //Permit access to mem_ptr after BIOs are destroyed.
    BIO_free_all(b64_bio);  //Destroys all BIOs in chain, starting with b64 (i.e. the 1st one).
    BUF_MEM_grow(mem_bio_mem_ptr, (*mem_bio_mem_ptr).length + 1);   //Makes space for end null.
    (*mem_bio_mem_ptr).data[(*mem_bio_mem_ptr).length] = '\0';  //Adds null-terminator to tail.
    return (*mem_bio_mem_ptr).data; //Returns base-64 encoded data. (See: "buf_mem_st" struct).
}

char *base64decode (const void *b64_decode_this, int decode_this_many_bytes)
{
    BIO *b64_bio, *mem_bio;      //Declares two OpenSSL BIOs: a base64 filter and a memory BIO.
    char *base64_decoded = calloc( (decode_this_many_bytes*3)/4+1, sizeof(char) ); //+1 = null.
    b64_bio = BIO_new(BIO_f_base64());                      //Initialize our base64 filter BIO.
    mem_bio = BIO_new(BIO_s_mem());                         //Initialize our memory source BIO.
    BIO_write(mem_bio, b64_decode_this, decode_this_many_bytes); //Base64 data saved in source.
    BIO_push(b64_bio, mem_bio);          //Link the BIOs by creating a filter-source BIO chain.
    BIO_set_flags(b64_bio, BIO_FLAGS_BASE64_NO_NL);          //Don't require trailing newlines.
    int decoded_byte_index = 0;   //Index where the next base64_decoded byte should be written.
    while ( 0 < BIO_read(b64_bio, base64_decoded+decoded_byte_index, 1) ){ //Read byte-by-byte.
        decoded_byte_index++; //Increment the index until read of BIO decoded data is complete.
    } //Once we're done reading decoded data, BIO_read returns -1 even though there's no error.
    BIO_free_all(b64_bio);  //Destroys all BIOs in chain, starting with b64 (i.e. the 1st one).
    return base64_decoded;        //Returns base-64 decoded data with trailing null terminator.
}

int encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key, unsigned char *iv, unsigned char *ciphertext)
{
    EVP_CIPHER_CTX *ctx;

    int len;

    int ciphertext_len;

    /* Create and initialise the context */
    ctx = EVP_CIPHER_CTX_new();

    /* Initialise the encryption operation */
    EVP_EncryptInit_ex(ctx, EVP_aes_128_ctr(), NULL, key, iv);

    /* Provide the message to be encrypted, and obtain the encrypted output.
     * EVP_EncryptUpdate can be called multiple times if necessary
     */
    EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len);
    ciphertext_len = len;

    /* Finalise the encryption. Further ciphertext bytes may be written at
     * this stage.
     */
    EVP_EncryptFinal_ex(ctx, ciphertext + len, &len);
    ciphertext_len += len;

    /* Clean up */
    EVP_CIPHER_CTX_free(ctx);

    return ciphertext_len;
}

int main (void)
{
    /* A 256 bit key */
    char keyStr[] = "5gYDRl00XcjqlcC5okdBSfDx46HIGZBMAvMiibVYixc=";
    unsigned char *key = (unsigned char *)base64decode(keyStr, strlen(keyStr));

    /* A 128 bit IV */
    char ivStr[] = "AAAAAAAAAAAAAAAAAAAAAA==";
    unsigned char *iv = (unsigned char *)base64decode(ivStr, strlen(ivStr));

    /* Message to be encrypted */
    unsigned char *plaintext = (unsigned char *)"This is a plaintext message.";

    /* Buffer for ciphertext */
    unsigned char ciphertext[128];
    int ciphertext_len;

    /* Initialise the library */
    OpenSSL_add_all_algorithms();
    OPENSSL_config(NULL);

    /* Encrypt the plaintext */
    ciphertext_len = encrypt (plaintext, strlen ((char *)plaintext), key, iv,
                              ciphertext);

    /* Encode with Base64 */
    char *ciphertextBase64 = base64encode(ciphertext, strlen(ciphertext));
    printf("Ciphertext is: %s\n", ciphertextBase64); /* print: UL4lvWZNtDVO64ywHVkFM/uBv+lpE3DhGZrRcw== */

    /* Clean up */
    EVP_cleanup();

    return 0;
}

So how I can get the same result sTBJYaaGNTxCErAXbP6eXnU59Yyn1UJAp7MGQw== in C?

3
  • 1
    You should not use AES_encrypt and friends for OpenSSL. That's a software-only implementation, so you will not enjoy hardware support, like AES-NI. You should be using EVP_* functions. See EVP Symmetric Encryption and Decryption on the OpenSSL wiki. Commented Sep 20, 2016 at 14:50
  • I rewrote C code with EVP_* functions. Anyway I got wrong ciphertext. Commented Sep 20, 2016 at 18:50
  • 1
    OpenSSL is likely adding padding. It should not matter expect for the last block, but I get the impression you have not gotten that far. Checkout EVP_CIPHER_CTX_set_padding. I'm guessing your immediate problem is decoding the Base64 strings. You have ntot stated anything about them, so its only speculation. Perhaps you should backup and use some hard coded keys and ivs? Commented Sep 20, 2016 at 23:30

1 Answer 1

0

Here AES CTR 256 not 128. Java do not explicity define bits it implicity gets from key size. So here key size has 32 bytes - 256 bits. I wrongly think that here AES CTR 128.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.