forked from icsharpcode/SharpZipLib
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
197 additions
and
5 deletions.
There are no files selected for viewing
157 changes: 157 additions & 0 deletions
157
src/ICSharpCode.SharpZipLib/Encryption/ZipAESEncryptionStream.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
using System; | ||
using System.IO; | ||
using System.Security.Cryptography; | ||
using ICSharpCode.SharpZipLib.Core; | ||
|
||
namespace ICSharpCode.SharpZipLib.Encryption | ||
{ | ||
/// <summary> | ||
/// Encrypts AES ZIP entries. | ||
/// </summary> | ||
/// <remarks> | ||
/// Based on information from http://www.winzip.com/aes_info.htm | ||
/// and http://www.gladman.me.uk/cryptography_technology/fileencrypt/ | ||
/// </remarks> | ||
internal class ZipAESEncryptionStream : Stream | ||
{ | ||
// The transform to use for encryption. | ||
private readonly ZipAESTransform transform; | ||
|
||
// The output stream to write the encrypted data to. | ||
private readonly Stream outputStream; | ||
|
||
// Static to help ensure that multiple files within a zip will get different random salt | ||
private static RandomNumberGenerator _aesRnd = RandomNumberGenerator.Create(); | ||
|
||
/// <summary> | ||
/// Constructor | ||
/// </summary> | ||
/// <param name="stream">The stream on which to perform the cryptographic transformation.</param> | ||
/// <param name="rawPassword">The password used to encrypt the entry.</param> | ||
/// <param name="saltLength">The length of the salt to use.</param> | ||
/// <param name="blockSize">The block size to use for transforming.</param> | ||
public ZipAESEncryptionStream(Stream stream, string rawPassword, int saltLength, int blockSize) | ||
{ | ||
// Set up stream. | ||
this.outputStream = stream; | ||
|
||
// Initialise the encryption transform. | ||
var salt = new byte[saltLength]; | ||
|
||
// Salt needs to be cryptographically random, and unique per file | ||
if (_aesRnd == null) | ||
_aesRnd = RandomNumberGenerator.Create(); | ||
_aesRnd.GetBytes(salt); | ||
|
||
this.transform = new ZipAESTransform(rawPassword, salt, blockSize, false); | ||
|
||
// File format for AES: | ||
// Size (bytes) Content | ||
// ------------ ------- | ||
// Variable Salt value | ||
// 2 Password verification value | ||
// Variable Encrypted file data | ||
// 10 Authentication code | ||
// | ||
// Value in the "compressed size" fields of the local file header and the central directory entry | ||
// is the total size of all the items listed above. In other words, it is the total size of the | ||
// salt value, password verification value, encrypted data, and authentication code. | ||
var pwdVerifier = this.transform.PwdVerifier; | ||
this.outputStream.Write(salt, 0, salt.Length); | ||
this.outputStream.Write(pwdVerifier, 0, pwdVerifier.Length); | ||
} | ||
|
||
// The final n bytes of the AES stream contain the Auth Code. | ||
private const int AUTH_CODE_LENGTH = 10; | ||
|
||
// Blocksize is always 16 here, even for AES-256 which has transform.InputBlockSize of 32. | ||
private const int CRYPTO_BLOCK_SIZE = 16; | ||
|
||
// total length of block + auth code | ||
private const int BLOCK_AND_AUTH = CRYPTO_BLOCK_SIZE + AUTH_CODE_LENGTH; | ||
|
||
|
||
private byte[] _slideBuffer; | ||
private int _slideBufStartPos; | ||
private int _slideBufFreePos; | ||
|
||
// Buffer block transforms to enable partial reads | ||
private byte[] _transformBuffer = null;// new byte[CRYPTO_BLOCK_SIZE]; | ||
private int _transformBufferFreePos; | ||
private int _transformBufferStartPos; | ||
|
||
// Do we have some buffered data available? | ||
private bool HasBufferedData =>_transformBuffer != null && _transformBufferStartPos < _transformBufferFreePos; | ||
|
||
// This stream is write only. | ||
public override bool CanRead => false; | ||
|
||
// We only support writing - no seeking about. | ||
public override bool CanSeek => false; | ||
|
||
// Supports writing for encrypting. | ||
public override bool CanWrite => true; | ||
|
||
// We don'tr track this. | ||
public override long Length => throw new NotImplementedException(); | ||
|
||
// We don't track this, or suppor tseeking. | ||
public override long Position { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } | ||
|
||
/// <summary> | ||
/// When the stream is closed, write the final blocks and AES Authentication code | ||
/// </summary> | ||
public override void Close() | ||
{ | ||
// Transform the final block. | ||
|
||
|
||
// Write the AES Authentication Code (a hash of the compressed and encrypted data) | ||
var authCode = this.transform.GetAuthCode(); | ||
this.outputStream.Write(authCode, 0, 10); | ||
} | ||
|
||
// <inheritdoc/> | ||
public override void Flush() | ||
{ | ||
this.outputStream.Flush(); | ||
} | ||
|
||
// <inheritdoc/> | ||
public override int Read(byte[] buffer, int offset, int count) | ||
{ | ||
// ZipAESEncryptionStream is only used for encryption. | ||
throw new NotImplementedException(); | ||
} | ||
|
||
// <inheritdoc/> | ||
public override long Seek(long offset, SeekOrigin origin) | ||
{ | ||
// We don't support seeking. | ||
throw new NotImplementedException(); | ||
} | ||
|
||
// <inheritdoc/> | ||
public override void SetLength(long value) | ||
{ | ||
// We don't support setting the length. | ||
throw new NotImplementedException(); | ||
} | ||
|
||
/// <summary> | ||
/// Writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written. | ||
/// </summary> | ||
/// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream. </param> | ||
/// <param name="offset">The byte offset in buffer at which to begin copying bytes to the current stream. </param> | ||
/// <param name="count">The number of bytes to be written to the current stream. </param> | ||
public override void Write(byte[] buffer, int offset, int count) | ||
{ | ||
if (count == 0) | ||
{ | ||
return; | ||
} | ||
|
||
|
||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters