Java และ openssl C ผลการเข้ารหัส AES CTR ที่แตกต่างกัน

ฉันต้องการย้ายแอปพลิเคชันจาก Java ไปยัง C++ ฉันติดอยู่กับปัญหากับ AES CTR 128 ใน Java และ C มีผลการเข้ารหัสที่แตกต่างกัน ดังนั้นโค้ด Java ของฉัน

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

รหัส C ของฉัน ฉันใช้อัลกอริทึม ข้อความธรรมดา คีย์ และ iv เดียวกัน แต่รับผลลัพธ์ข้อความตัวเลขอื่น

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

แล้วฉันจะได้รับผลลัพธ์เดียวกัน sTBJYaaGNTxCErAXbP6eXnU59Yyn1UJAp7MGQw== ใน C ได้อย่างไร


person Ivan Romanov    schedule 20.09.2016    source แหล่งที่มา
comment
คุณไม่ควร ไม่ ใช้ AES_encrypt และเพื่อนสำหรับ OpenSSL นั่นเป็นการใช้งานซอฟต์แวร์เท่านั้น ดังนั้นคุณจะไม่ได้รับการสนับสนุนจากฮาร์ดแวร์ เช่น AES-NI คุณควรใช้ฟังก์ชัน EVP_* ดู EVP Symmetric Encryption and Decryption บนวิกิ OpenSSL   -  person jww    schedule 20.09.2016
comment
ฉันเขียนโค้ด C ใหม่ด้วยฟังก์ชัน EVP_* ยังไงซะฉันก็มีไซเฟอร์เท็กซ์ผิด   -  person Ivan Romanov    schedule 20.09.2016
comment
OpenSSL มีแนวโน้มที่จะเพิ่มช่องว่างภายใน มันไม่ควรเป็นเรื่องสำคัญที่คาดหวังสำหรับบล็อกสุดท้าย แต่ฉันรู้สึกว่าคุณยังมาไม่ถึงขนาดนั้น ชำระเงิน EVP_CIPHER_CTX_set_padding ฉันเดาว่าปัญหาเฉพาะหน้าของคุณคือการถอดรหัสสตริง Base64 คุณไม่ได้ระบุอะไรเกี่ยวกับพวกเขา ดังนั้นจึงเป็นเพียงการคาดเดาเท่านั้น บางทีคุณควรสำรองข้อมูลและใช้คีย์ฮาร์ดโค้ดและ ivs   -  person jww    schedule 21.09.2016


คำตอบ (1)


ที่นี่ AES CTR 256 ไม่ใช่ 128 Java ไม่ได้กำหนดบิตอย่างชัดเจนโดยนัยที่ได้รับจากขนาดคีย์ ดังนั้นขนาดคีย์ที่นี่จึงมี 32 ไบต์ - 256 บิต ฉันคิดผิดว่าที่นี่ AES CTR 128

person Ivan Romanov    schedule 21.09.2016