2015-12-30 11:19:42 +00:00
|
|
|
using System;
|
2019-12-30 18:58:25 +01:00
|
|
|
using System.Buffers.Binary;
|
2016-02-13 09:42:59 +00:00
|
|
|
using System.Security.Cryptography;
|
2025-11-29 11:03:48 +00:00
|
|
|
using System.Text;
|
2015-12-30 11:19:42 +00:00
|
|
|
|
2022-12-20 15:06:44 +00:00
|
|
|
namespace SharpCompress.Common.Zip;
|
|
|
|
|
|
|
|
|
|
internal class WinzipAesEncryptionData
|
2015-12-30 11:19:42 +00:00
|
|
|
{
|
2022-12-20 15:06:44 +00:00
|
|
|
private const int RFC2898_ITERATIONS = 1000;
|
2015-12-30 11:19:42 +00:00
|
|
|
|
2022-12-20 15:06:44 +00:00
|
|
|
private readonly WinzipAesKeySize _keySize;
|
2015-12-30 11:19:42 +00:00
|
|
|
|
2022-12-20 15:06:44 +00:00
|
|
|
internal WinzipAesEncryptionData(
|
|
|
|
|
WinzipAesKeySize keySize,
|
|
|
|
|
byte[] salt,
|
|
|
|
|
byte[] passwordVerifyValue,
|
|
|
|
|
string password
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
_keySize = keySize;
|
2024-04-23 09:59:30 +01:00
|
|
|
|
2025-11-29 11:42:05 +00:00
|
|
|
#if NETFRAMEWORK
|
2024-04-23 09:59:30 +01:00
|
|
|
var rfc2898 = new Rfc2898DeriveBytes(password, salt, RFC2898_ITERATIONS);
|
2025-11-29 11:03:48 +00:00
|
|
|
KeyBytes = rfc2898.GetBytes(KeySizeInBytes);
|
|
|
|
|
IvBytes = rfc2898.GetBytes(KeySizeInBytes);
|
|
|
|
|
var generatedVerifyValue = rfc2898.GetBytes(2);
|
|
|
|
|
#elif NET10_0_OR_GREATER
|
|
|
|
|
var derivedKeySize = (KeySizeInBytes * 2) + 2;
|
|
|
|
|
var passwordBytes = Encoding.UTF8.GetBytes(password);
|
|
|
|
|
var derivedKey = Rfc2898DeriveBytes.Pbkdf2(
|
|
|
|
|
passwordBytes,
|
|
|
|
|
salt,
|
|
|
|
|
RFC2898_ITERATIONS,
|
|
|
|
|
HashAlgorithmName.SHA1,
|
|
|
|
|
derivedKeySize
|
|
|
|
|
);
|
|
|
|
|
KeyBytes = derivedKey.AsSpan(0, KeySizeInBytes).ToArray();
|
|
|
|
|
IvBytes = derivedKey.AsSpan(KeySizeInBytes, KeySizeInBytes).ToArray();
|
|
|
|
|
var generatedVerifyValue = derivedKey.AsSpan((KeySizeInBytes * 2), 2).ToArray();
|
2024-04-23 09:59:30 +01:00
|
|
|
#else
|
|
|
|
|
var rfc2898 = new Rfc2898DeriveBytes(
|
|
|
|
|
password,
|
|
|
|
|
salt,
|
|
|
|
|
RFC2898_ITERATIONS,
|
|
|
|
|
HashAlgorithmName.SHA1
|
|
|
|
|
);
|
2025-11-29 11:03:48 +00:00
|
|
|
KeyBytes = rfc2898.GetBytes(KeySizeInBytes);
|
2024-04-23 09:59:30 +01:00
|
|
|
IvBytes = rfc2898.GetBytes(KeySizeInBytes);
|
|
|
|
|
var generatedVerifyValue = rfc2898.GetBytes(2);
|
2025-11-29 11:03:48 +00:00
|
|
|
#endif
|
2024-04-23 09:59:30 +01:00
|
|
|
|
|
|
|
|
var verify = BinaryPrimitives.ReadInt16LittleEndian(passwordVerifyValue);
|
|
|
|
|
var generated = BinaryPrimitives.ReadInt16LittleEndian(generatedVerifyValue);
|
|
|
|
|
if (verify != generated)
|
|
|
|
|
{
|
|
|
|
|
throw new InvalidFormatException("bad password");
|
|
|
|
|
}
|
2022-12-20 15:06:44 +00:00
|
|
|
}
|
2015-12-30 11:19:42 +00:00
|
|
|
|
2022-12-20 15:06:44 +00:00
|
|
|
internal byte[] IvBytes { get; set; }
|
2020-05-23 16:27:55 -07:00
|
|
|
|
2022-12-20 15:06:44 +00:00
|
|
|
internal byte[] KeyBytes { get; set; }
|
2015-12-30 11:19:42 +00:00
|
|
|
|
2022-12-20 15:20:49 +00:00
|
|
|
private int KeySizeInBytes => KeyLengthInBytes(_keySize);
|
2015-12-30 11:19:42 +00:00
|
|
|
|
2022-12-20 15:20:49 +00:00
|
|
|
internal static int KeyLengthInBytes(WinzipAesKeySize keySize) =>
|
|
|
|
|
keySize switch
|
2015-12-30 11:19:42 +00:00
|
|
|
{
|
2022-12-20 15:06:44 +00:00
|
|
|
WinzipAesKeySize.KeySize128 => 16,
|
|
|
|
|
WinzipAesKeySize.KeySize192 => 24,
|
|
|
|
|
WinzipAesKeySize.KeySize256 => 32,
|
|
|
|
|
_ => throw new InvalidOperationException(),
|
|
|
|
|
};
|
2015-12-30 11:19:42 +00:00
|
|
|
}
|