<PackageReference Include="BouncyCastle.Cryptography" Version="2.7.0-beta.98" />

S2k

public class S2k : BcpgObject
using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities; using System; using System.IO; namespace Org.BouncyCastle.Bcpg { public class S2k : BcpgObject { public sealed class Argon2Params { private readonly byte[] m_salt; private readonly int m_passes; private readonly int m_parallelism; private readonly int m_memorySizeExponent; public int MemorySizeExponent => m_memorySizeExponent; public int Parallelism => m_parallelism; public int Passes => m_passes; public static SecureRandom DefaultSecureRandom() { return CryptoServicesRegistrar.GetSecureRandom(); } public static Argon2Params MemoryConstrainedParameters(SecureRandom secureRandom) { return new Argon2Params(3, 4, 16, secureRandom); } public static Argon2Params RecommendedParameters(SecureRandom secureRandom) { return new Argon2Params(1, 4, 21, secureRandom); } public Argon2Params(int passes, int parallelism, int memorySizeExponent, SecureRandom secureRandom) : this(GenerateSalt(secureRandom), passes, parallelism, memorySizeExponent) { } public Argon2Params(byte[] salt, int passes, int parallelism, int memorySizeExponent) { if (salt.Length != 16) throw new ArgumentException("Argon2 uses 16 bytes of salt", "salt"); if (passes < 1 || passes > 255) throw new ArgumentOutOfRangeException("passes", passes, "MUST be an integer value from 1 to 255."); if (parallelism < 1 || parallelism > 255) throw new ArgumentOutOfRangeException("parallelism", parallelism, "MUST be an integer value from 1 to 255."); int num = 35 - Integers.NumberOfLeadingZeros(parallelism - 1); int num2 = 30; if (memorySizeExponent < num || memorySizeExponent > num2) throw new ArgumentOutOfRangeException("memorySizeExponent", memorySizeExponent, "MUST be an integer value from 3 + bitlen(parallelism - 1) to 30."); m_salt = Arrays.Clone(salt); m_passes = passes; m_parallelism = parallelism; m_memorySizeExponent = memorySizeExponent; } public byte[] GetSalt() { return Arrays.Clone(m_salt); } private static byte[] GenerateSalt(SecureRandom secureRandom) { return SecureRandom.GetNextBytes(secureRandom, 16); } } private const int ExpBias = 6; public const int Simple = 0; public const int Salted = 1; public const int SaltedAndIterated = 3; public const int Argon2 = 4; public const int GnuDummyS2K = 101; public const int GnuProtectionModeNoPrivateKey = 1; public const int GnuProtectionModeDivertToCard = 2; public const int GnuProtectionModeInternal = 3; internal int m_type; internal HashAlgorithmTag m_algorithm; internal byte[] m_iv; internal int m_itCount = -1; internal int m_protectionMode = -1; internal Argon2Params m_argon2Config; public virtual int Type => m_type; public virtual HashAlgorithmTag HashAlgorithm => m_algorithm; public virtual long IterationCount { get { if (m_itCount < 256) return DeriveIterationCount(m_itCount); return m_itCount; } } public virtual int ProtectionMode => m_protectionMode; public virtual Argon2Params Argon2Config => m_argon2Config; public static S2k GenerateSalted(SecureRandom secureRandom, HashAlgorithmTag hashAlgorithm) { byte[] iv = GenerateIV(secureRandom); return new S2k(hashAlgorithm, iv); } public static S2k GenerateSaltedAndIterated(SecureRandom secureRandom, HashAlgorithmTag hashAlgorithm, int itCount) { byte[] iv = GenerateIV(secureRandom); return new S2k(hashAlgorithm, iv, itCount); } internal S2k(Stream inStr) { m_type = StreamUtilities.RequireByte(inStr); switch (m_type) { case 0: m_algorithm = (HashAlgorithmTag)StreamUtilities.RequireByte(inStr); break; case 1: m_algorithm = (HashAlgorithmTag)StreamUtilities.RequireByte(inStr); m_iv = StreamUtilities.RequireBytes(inStr, 8); break; case 3: m_algorithm = (HashAlgorithmTag)StreamUtilities.RequireByte(inStr); m_iv = StreamUtilities.RequireBytes(inStr, 8); m_itCount = StreamUtilities.RequireByte(inStr); break; case 4: { byte[] salt = StreamUtilities.RequireBytes(inStr, 16); byte passes = StreamUtilities.RequireByte(inStr); byte parallelism = StreamUtilities.RequireByte(inStr); byte memorySizeExponent = StreamUtilities.RequireByte(inStr); m_argon2Config = new Argon2Params(salt, passes, parallelism, memorySizeExponent); break; } case 101: { m_algorithm = (HashAlgorithmTag)StreamUtilities.RequireByte(inStr); uint num = StreamUtilities.RequireUInt32BE(inStr); m_protectionMode = (byte)num; break; } default: throw new UnsupportedPacketVersionException("Invalid S2K type: " + m_type.ToString()); } } public S2k(HashAlgorithmTag algorithm) { m_type = 0; m_algorithm = algorithm; } public S2k(HashAlgorithmTag algorithm, byte[] iv) { m_type = 1; m_algorithm = algorithm; m_iv = iv; } public S2k(HashAlgorithmTag algorithm, byte[] iv, int itCount) { m_type = 3; m_algorithm = algorithm; m_iv = iv; m_itCount = itCount; } public S2k(Argon2Params argon2Config) { m_type = 4; if (argon2Config == null) throw new ArgumentNullException("argon2Config"); m_argon2Config = argon2Config; } public virtual byte[] GetIV() { return Arrays.Clone(m_iv); } public override void Encode(BcpgOutputStream bcpgOut) { bcpgOut.WriteByte((byte)m_type); switch (m_type) { case 0: bcpgOut.WriteByte((byte)m_algorithm); break; case 1: bcpgOut.WriteByte((byte)m_algorithm); bcpgOut.Write(m_iv); break; case 3: bcpgOut.WriteByte((byte)m_algorithm); bcpgOut.Write(m_iv); WriteCheckedByte(bcpgOut, m_itCount, "Iteration count"); break; case 4: bcpgOut.Write(m_argon2Config.GetSalt()); WriteCheckedByte(bcpgOut, m_argon2Config.Passes, "Passes"); WriteCheckedByte(bcpgOut, m_argon2Config.Parallelism, "Parallelism"); WriteCheckedByte(bcpgOut, m_argon2Config.MemorySizeExponent, "Memory size exponent"); break; case 101: { byte[] obj = new byte[5] { 0, 71, 78, 85, 0 }; obj[0] = (byte)m_algorithm; obj[4] = (byte)m_protectionMode; bcpgOut.Write(obj); break; } default: throw new InvalidOperationException("Unknown S2K type " + m_type.ToString()); } } private static long DeriveIterationCount(int itCount) { return 16 + (itCount & 15) << (itCount >> 4) + 6; } private static byte[] GenerateIV(SecureRandom secureRandom) { return SecureRandom.GetNextBytes(secureRandom, 8); } private static void WriteCheckedByte(BcpgOutputStream bcpgOut, int val, string valName) { if ((val & 4294967040) != 0) throw new InvalidOperationException(valName + " not encodable"); bcpgOut.WriteByte((byte)val); } } }