2012-03-15 25 views
16

Tôi biết cách AES mã hóa và giải mã NSData, nhưng điều đó yêu cầu tải toàn bộ tệp vào bộ nhớ trước.IOS - Làm cách nào để AES giải mã một tệp lớn nếu tệp quá lớn để tải tất cả tệp đó vào bộ nhớ?

Giả sử tôi có tệp được mã hóa 50mb có tên là data.dat.enc, làm cách nào tôi có thể giải mã tệp thành một tệp data.dat mà không phải tải tất cả vào bộ nhớ trước tiên?

+0

Tại sao không chia nhỏ dữ liệu trước khi mã hóa, sau đó không mã hóa và đặt lại với nhau? –

+0

@PRNDLDevelopmentStudios Có, tôi cho rằng tôi sẽ làm điều đó nếu tôi phải làm, nhưng tôi có nhiều tệp lớn và sẽ khó quản lý một loạt các tệp được chia nhỏ hơn. – Kyle

+0

Bạn có thể thử nén dữ liệu trước khi mã hóa, nhưng tôi không biết liệu tỷ lệ nén có đủ cao để thực sự quan trọng hay không. Có thể mở kết nối SSL đến máy chủ, tải lên dữ liệu đã mã hóa, giải mã máy chủ và gửi lại? –

Trả lời

15

EDIT: Mã này đã được mở rộng bởi http://github.com/rnapier/RNCryptor.


RNCryptManager là ví dụ tốt về cách thực hiện việc này. Nó xuất phát từ mã mẫu chương 11 của iOS5:PTL. Hãy xem:

+ (BOOL)decryptFromStream:(NSInputStream *)fromStream 
       toStream:(NSOutputStream *)toStream 
       password:(NSString *)password 
        error:(NSError **)error; 

Giả định rằng muối và IV đã được thêm vào luồng (điều này được giải thích trong sách). Để biết thêm một số thảo luận chung về mã hóa AES, hãy xem Properly encrypting with AES with CommonCrypto.

Để biết ví dụ về cách sử dụng, hãy xem CPCryptController.m trong cùng một dự án.

Nếu có đủ sự quan tâm, tôi có thể kéo đối tượng này ra và hỗ trợ nó như là một dự án độc lập thay vì chỉ là một đoạn mã mẫu. Nó có vẻ hợp lý hữu ích cho mọi người. Nhưng không khó để tích hợp như vậy.

Câu trả lời chung hơn là bạn tạo một mật mã với CCCryptorCreate và sau đó thực hiện cuộc gọi đến CCCryptorUpdate cho mỗi khối. Sau đó, bạn gọi CCCryptorFinal để hoàn thành mọi thứ.

+0

+1 Không thể lỗi câu trả lời đó. Có thể đoán rằng sẽ có một chức năng cập nhật ở đâu đó bằng cách nào đó. –

+0

Chỉ cần hoàn thành kiểm tra nó. Cám ơn rất nhiều! Nó hoạt động hoàn hảo :) – Kyle

+0

@Rob Trong thử nghiệm của tôi, tôi thấy rằng giải mã một tập tin được mã hóa với mật khẩu sai đôi khi có thể trả về 'true' từ hàm này (khoảng 0,5% thời gian). Kết quả "giải mã" tập tin không thực sự giải mã, nó chỉ là dữ liệu rác, nhưng chức năng vẫn trả về 'true'. Đây có phải là hành vi dự định không? Nếu vậy, làm thế nào tôi có thể phát hiện nếu giải mã đã thực sự thành công? – Kyle

0

Bạn có hai lựa chọn (và ở đây tôi mô tả quá trình mã hóa mà thôi, nhưng giải mã tương tự):

Sử dụng một mật mã dòng (như AES-CTR)

Bạn khởi tạo mật mã với một Phím 16 byte và thực sự ngẫu nhiên 16 byte nonce, viết nonce, tải phần đầu tiên, mã hóa nó, viết kết quả, tải một mảnh thứ hai và vv. Lưu ý rằng bạn phải khởi tạo mật mã chỉ một lần. Kích thước của mảnh có thể tùy ý; nó thậm chí không cần phải giống nhau mỗi lần.

Sử dụng một thuật toán mã hóa khối với một chế độ chaining một vượt qua, ví dụ AES128-CBC

Bạn khởi tạo mật mã với khóa gồm 16 byte, tạo ra một ngẫu nhiên 16 byte IV, viết IV, viết tổng số chiều dài của tập tin, tải phần đầu tiên, mã hóa nó cùng với IV, ghi kết quả, tải một mảnh thứ hai, mã hóa bằng cách sử dụng 16 byte cuối cùng của khối mã hóa trước đó dưới dạng IV, ghi kết quả, v.v. Kích thước của mảnh phải là bội số của 16 byte; một lần nữa, nó thậm chí không cần phải giống nhau mỗi lần. Bạn có thể cần phải pad khối cuối cùng với số không.

Trong cả hai trường hợp

Bạn phải tính toán băm mật mã của file được mã hóa ban đầu (ví dụ sử dụng SHA-256) và viết nó khi mã hóa được hoàn tất. Điều đó khá dễ dàng: bạn khởi tạo băm ngay từ đầu, và nạp mỗi khối vào nó ngay sau khi nó được nạp (bao gồm nonce/IV và có thể là trường độ dài). Ở phía giải mã, bạn cũng làm như vậy. Cuối cùng, bạn phải xác minh rằng thông tin được tính toán phù hợp với thông tin đi kèm với tệp được mã hóa.

Làm cách nào để thực hiện trên iOS? Tôi sợ tôi không quen với nền tảng này, nhưng CCCypt dường như phù hợp với hóa đơn.

CHỈNH SỬA: nonce/IV và độ dài cũng được băm.

+3

Trước hết, có rất nhiều vấn đề với việc sử dụng RC4, hãy đọc trang wikipedia. RC4 không sử dụng IV, mặc dù một số triển khai có thể gọi một số phần tử là IV. Đoạn thứ hai, sử dụng AES128-CBC là hoàn toàn tốt như là một giải pháp, ngoại trừ padding với số không. Chỉ cần tính băm trên văn bản thuần túy không phải là một ý tưởng hay, nếu chỉ vì bạn sẽ rò rỉ thông tin về văn bản thuần túy (mã hóa cùng một văn bản thuần tuý hai lần và bạn có thể so sánh kết quả, đặt tên cho một vấn đề). –

+0

Nếu bạn đăng giải pháp CBC của bạn như là một câu trả lời riêng biệt, đề xuất sử dụng đệm PKCS # 7 thay vì không đệm, tôi sẽ sẵn lòng bỏ phiếu cho nó. Điều này bị bỏ phiếu vì nhiều lỗi bổ sung. –

+0

Lưu ý rằng mã nguồn gốc của OP gần như chắc chắn sử dụng CBC. Đó là mặc định trong thư viện iOS. Có hầu như không bao giờ là một lý do để sử dụng EBC (chế độ khác), bất kể bạn đang mã hóa/giải mã tất cả cùng một lúc hay "khi bạn đi". PKCS # 7 padding cũng là padding duy nhất được hỗ trợ bởi các thư viện iOS, do đó, có khả năng nó cũng đã được sử dụng (trừ khi tải trọng không yêu cầu đệm). –

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