2014-10-13 19 views
9

Tôi đang sử dụng SSL mở trong chương trình của mình, để mã hóa và giải mã dữ liệu bằng cách sử dụng mật mã aes. Tại thời điểm này có một chút rò rỉ bộ nhớ, vì vậy tôi đang tìm cách sửa lỗi đó. Trong thói quen giải mã mã hóa của tôi, tôi có bối cảnh tự do như vậyCách chính xác để giải phóng/phân bổ bối cảnh trong OpenSSL

EVP_CIPHER_CTX_free(ctx); 

Và tạo ra bởi:

EVP_CIPHER_CTX_new 

Đây là trên trang wiki OpenSSL trong examples

Nhưng! Trên trang MAN, có một gợi ý cho việc sử dụng các hàm EVP_CIPHER_CTX_cleanupEVP_CIPHER_CTX_init. Vì vậy, về cơ bản những gì nên được chính xác để sử dụng, là EVP_CIPHER_CTX_new/EVP_CIPHER_CTX_free bằng cách nào đó không được chấp nhận? Và có bất kỳ sự khác biệt lớn nào giữa EVP_CIPHER_CTX_new/EVP_CIPHER_CTX_freeEVP_CIPHER_CTX_init/EVP_CIPHER_CTX_cleanup không?

if(!(ctx = EVP_CIPHER_CTX_new())) return -1; 


    if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv)) 
    { 
    EVP_CIPHER_CTX_free(ctx); 
    return -1; 
    } 

    if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len)) 
    { 
    EVP_CIPHER_CTX_free(ctx); 
    return -1; 
    } 
    ciphertext_len = len; 


    if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) { EVP_CIPHER_CTX_free(ctx); return -1; } 
    ciphertext_len += len; 


    EVP_CIPHER_CTX_free(ctx); 

Trả lời

0

Được rồi, tôi nghĩ nó đã bị xóa ngay bây giờ. Nếu bạn làm EVP phong cách mã hóa/giải mã, chắc chắn rằng bạn tạo ra bối cảnh như vậy:

EVP_CIPHER_CTX ctx; 
    EVP_CIPHER_CTX_init(&ctx); 

Và miễn phí nó như vậy:

EVP_CIPHER_CTX_cleanup(&ctx); 

Không sử dụng EVP_CIPHER_CTX_new/EVP_CIPHER_CTX_free để tạo/miễn phí bối cảnh, họ không được chấp nhận!

+6

Đó là điều ngược lại tôi nghĩ. Trong thực tế openssl-1.1.0 làm cho EVP_CIPHER_CTX trở thành một dạng mờ, do đó, biểu mẫu đầu tiên ở trên là một lỗi biên dịch – pixelbeat

+1

Câu trả lời này có chính xác ngược như đã nêu trong các câu trả lời khác. Vui lòng cập nhật hoặc hủy chấp nhận nó. – rdb

5

Bạn không nên sử dụng EVP_EncryptInit nữa. Chức năng đó đã tự động tạo ra một ngữ cảnh cụ thể, nhưng nó không hỗ trợ các công cụ mã hóa mà sau này đã được thêm vào. Tuy nhiên, EVP_EncryptInit_ex tuyên bố rõ ràng rằng:

ctx phải được khởi tạo trước khi gọi chức năng này.

vì vậy bạn bắt buộc phải sử dụng EVP_CIPHER_CTX_new tại đây tôi giả sử.

EVP_CIPHER_CTX_free là một vấn đề khác, có vẻ như đã không được chấp nhận, tôi không thấy bất kỳ đề cập nào về nó trên các trang thủ công của OpenSSL. Đó là thực hành tốt (và yêu cầu đối với chức năng được chứng nhận của NIST) để xóa tài liệu chính và trạng thái mã hóa khác sau khi sử dụng. Nếu không, kẻ tấn công có thể quét bộ nhớ hoặc sử dụng tràn ở giai đoạn sau.

Tên của EVP_CIPHER_CTX_free chỉ cho biết rằng bộ nhớ CTX sẽ được giải phóng. Nhưng giải phóng bộ nhớ không ngụ ý rằng nó được quét thông tin nhạy cảm trước; nó chỉ được trả lại cho hệ thống, không có nghĩa vụ ghi đè lên nó. Mặt khác, EVP_CIPHER_CTX_cleanup sẽ quét sạch thông tin đó trước khi giải phóng bộ nhớ (hoặc ít nhất nó cũng cố gắng làm như vậy, tôi đoán). Vì vậy, bạn cần phải gọi chức năng này sau khi bạn đã cung cấp tài liệu chính của mình.

+0

Tôi không nghĩ rằng vấn đề bộ nhớ của bạn là trong bối cảnh, nhìn vào mã của bạn. Bạn có thể thử một số thứ khác như máy phân tích mã tĩnh. –

8

Trước hết, nếu bạn muốn có câu trả lời chính xác, bạn nên luôn chỉ định phiên bản OpenSSL bạn đang sử dụng. FYI 1.0.2 là phiên bản Long Term Support hiện tại, trong khi 1.1.0 là phiên bản mới nhất (vào tháng 9 năm 2016).

Nếu bạn đọc 1.1.0 trang người đàn ông bạn sẽ thấy:

EVP_CIPHER_CTX được làm mờ trong OpenSSL 1.1.0. Kết quả là, EVP_CIPHER_CTX_reset() đã xuất hiện và EVP_CIPHER_CTX_cleanup() biến mất. EVP_CIPHER_CTX_init() vẫn là bí danh cho EVP_CIPHER_CTX_reset().

Câu trả lời ngắn gọn là: bạn nên sử dụng EVP_CIPHER_CTX_new để khởi tạo và EVP_CIPHER_CTX_free giải phóng bộ nhớ, bất kể phiên bản nào, đây là lý do.

Phân bổ:

1.0.2 trang người đàn ông nói:

EVP_CIPHER_CTX ctx; 
EVP_CIPHER_CTX_init(&ctx); 

và 1.1.0 trang người đàn ông nói:

EVP_CIPHER_CTX *ctx; 
ctx = EVP_CIPHER_CTX_new(); 

Nếu bạn nhìn vào code của EVP_CIPHER_CTX_init trong 1.0.2

void EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *ctx) 
{ 
    memset(ctx, 0, sizeof(EVP_CIPHER_CTX)); 
    /* ctx->cipher=NULL; */ 
} 

khi EVP_CIPHER_CTX_new là:

EVP_CIPHER_CTX *EVP_CIPHER_CTX_new(void) 
{ 
    EVP_CIPHER_CTX *ctx = OPENSSL_malloc(sizeof *ctx); 
    if (ctx) 
     EVP_CIPHER_CTX_init(ctx); 
    return ctx; 
} 

vì vậy bạn bạn vẫn còn khấm khá hơn khởi tạo bối cảnh, giống như trong 1.1.0 Ví dụ:

EVP_CIPHER_CTX *ctx; 
ctx = EVP_CIPHER_CTX_new(); 

cho 1.1.0 cùng áp dụng.

Đối với giải phóng bộ nhớ:

1.0.2 man trang:

EVP_CIPHER_CTX_cleanup(&ctx); 

1.1.0 trang người đàn ông:

EVP_CIPHER_CTX_free(ctx); 

Nhưng nếu bạn đánh dấu vào code bạn có thể nhìn thấy cho 1.0.2:

void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *ctx) 
{ 
    if (ctx) { 
     EVP_CIPHER_CTX_cleanup(ctx); 
     OPENSSL_free(ctx); 
    } 
} 

Vì vậy, bạn nên sử dụng EVP_CIPHER_CTX_free để deallocating. Nếu bạn chỉ muốn đặt lại ngữ cảnh cho một thao tác khác thì EVP_CIPHER_CTX_cleanup (1.0.2) và EVP_CIPHER_CTX_reset (1.1.0) là bạn của bạn.

Nếu bạn tò mò về mallocmemsetcalloc, đây là một good explanation

Các vấn đề liên quan