Java dan openssl C berbeda hasil enkripsi AES CTR

Saya perlu mem-porting aplikasi dari Java ke C++. Saya mengalami masalah dengan AES CTR 128. Di Java dan C memiliki hasil enkripsi yang berbeda. Jadi kode Java saya.

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;
    }
}

Kode C saya. Saya menggunakan algoritma yang sama, teks biasa, kunci dan iv. Tapi dapatkan hasil cipher text yang lain.

#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;
}

Jadi bagaimana saya bisa mendapatkan hasil yang sama sTBJYaaGNTxCErAXbP6eXnU59Yyn1UJAp7MGQw== di C?


person Ivan Romanov    schedule 20.09.2016    source sumber
comment
Anda tidak boleh menggunakan AES_encrypt dan teman untuk OpenSSL. Itu adalah implementasi perangkat lunak saja, jadi Anda tidak akan menikmati dukungan perangkat keras, seperti AES-NI. Anda harus menggunakan fungsi EVP_*. Lihat Enkripsi dan Dekripsi Simetris EVP di wiki OpenSSL.   -  person jww    schedule 20.09.2016
comment
Saya menulis ulang kode C dengan fungsi EVP_*. Pokoknya saya salah mendapatkan ciphertext.   -  person Ivan Romanov    schedule 20.09.2016
comment
OpenSSL kemungkinan menambahkan padding. Seharusnya tidak menjadi masalah untuk mengharapkan blok terakhir, tapi saya mendapat kesan Anda belum sampai sejauh itu. Lihat EVP_CIPHER_CTX_set_padding. Saya kira masalah langsung Anda adalah mendekode string Base64. Anda belum menyatakan apa pun tentang mereka, jadi itu hanya spekulasi. Mungkin Anda harus membuat cadangan dan menggunakan beberapa kunci kode keras dan ivs?   -  person jww    schedule 21.09.2016


Jawaban (1)


Di sini AES CTR 256 bukan 128. Java tidak secara eksplisit mendefinisikan bit yang secara implisit didapat dari ukuran kunci. Jadi disini ukuran kuncinya adalah 32 byte - 256 bit. Saya salah mengira di sini AES CTR 128.

person Ivan Romanov    schedule 21.09.2016