/// <summary> /// CipherKey structure constructor. /// <para>KeyID and ExtRandom values must each be 16 bytes in length. /// If they are not specified they will be populated automatically.</para> /// </summary> /// /// <param name="Description">The <see cref="CipherDescription">CipherDescription</see> structure containing a complete description of the cipher instance</param> /// <param name="KeyId">The unique 16 byte ID field used to identify this key. A null value auto generates this field</param> /// <param name="ExtensionKey">An array of random bytes used to encrypt a message file extension. A null value auto generates this field</param> /// /// <exception cref="CryptoProcessingException">Thrown if either the KeyId or ExtensionKey fields are null or invalid</exception> public CipherKey(CipherDescription Description, byte[] KeyId = null, byte[] ExtensionKey = null) { this.Description = Description; if (KeyId == null) { this.KeyID = Guid.NewGuid().ToByteArray(); } else if (KeyId.Length != KEYID_SIZE) { throw new CryptoProcessingException("CipherKey:CTor", "The KeyId must be exactly 16 bytes!", new ArgumentOutOfRangeException()); } else { this.KeyID = KeyId; } if (ExtensionKey == null) { using (KeyGenerator gen = new KeyGenerator()) this.ExtensionKey = gen.GetBytes(16); } else if (ExtensionKey.Length != EXTKEY_SIZE) { throw new CryptoProcessingException("CipherKey:CTor", "The random extension field must be exactly 16 bytes!", new ArgumentOutOfRangeException()); } else { this.ExtensionKey = ExtensionKey; } }
/// <summary> /// Creates a temporary CipherKey on disk, extracts and compares the copy /// <para>Throws an Exception on failure</</para> /// </summary> public static void KeyFactoryTest() { string path = GetTempPath(); KeyParams key1; KeyParams key2; CipherKey cikey; CipherDescription desc; using (KeyFactory factory = new KeyFactory(path)) { // create a key/iv key1 = new KeyGenerator().GetKeyParams(32, 16, 64); // alt: manual creation /*kf.Create( kp, Engines.RDX, 32, IVSizes.V128, CipherModes.CTR, PaddingModes.X923, BlockSizes.B128, RoundCounts.R14, Digests.Keccak512, 64, Digests.Keccak512);*/ // cipher paramaters desc = new CipherDescription( SymmetricEngines.RDX, 32, IVSizes.V128, CipherModes.CTR, PaddingModes.X923, BlockSizes.B128, RoundCounts.R14, Digests.Keccak512, 64, Digests.Keccak512); // create the key factory.Create(desc, key1); // extract factory.Extract(out cikey, out key2); } if (!cikey.Description.Equals(desc)) throw new Exception(); // compare key material if (!Compare.AreEqual(key1.IKM, key2.IKM)) throw new Exception(); if (!Compare.AreEqual(key1.IV, key2.IV)) throw new Exception(); if (!Compare.AreEqual(key1.Key, key2.Key)) throw new Exception(); if (File.Exists(path)) File.Delete(path); }
/// <summary> /// Compare this object instance with another /// </summary> /// /// <param name="Obj">Object to compare</param> /// /// <returns>True if equal, otherwise false</returns> public override bool Equals(Object Obj) { if (!(Obj is CipherDescription)) { return(false); } CipherDescription other = (CipherDescription)Obj; if (EngineType != other.EngineType) { return(false); } if (KeySize != other.KeySize) { return(false); } if (IvSize != other.IvSize) { return(false); } if (CipherType != other.CipherType) { return(false); } if (PaddingType != other.PaddingType) { return(false); } if (BlockSize != other.BlockSize) { return(false); } if (RoundCount != other.RoundCount) { return(false); } if (KdfEngine != other.KdfEngine) { return(false); } if (MacKeySize != other.MacKeySize) { return(false); } if (MacEngine != other.MacEngine) { return(false); } return(true); }
/// <summary> /// Build the PackageInfo structure from a <see cref="PackageKey"/> file /// </summary> /// /// <param name="Package">Populated PackageKey structure</param> public PackageInfo(PackageKey Package) { Description = Package.Description; Created = new DateTime(Package.CreatedOn); Origin = new Guid(Package.Authority.OriginId); string ptg = System.Text.Encoding.ASCII.GetString(Package.Authority.PackageTag); Tag = ptg.Replace("\0", String.Empty); SubKeyCount = Package.SubKeyCount; Policies = new List<KeyPolicies>(); foreach (var flag in Enum.GetValues(typeof(KeyPolicies))) { if ((Package.Authority.KeyPolicy & (long)flag) == (long)flag) Policies.Add((KeyPolicies)flag); } if (Package.Authority.OptionFlag == 0) Expiration = DateTime.MaxValue; else Expiration = new DateTime(Package.Authority.OptionFlag); }
/// <summary> /// Extract the next valid subkey set (Expired flag not set) as a KeyParam, and a CipherDescription structure. /// <para>Used only when calling a Encryption function.</para> /// </summary> /// /// <param name="Description">out: The CipherDescription structure; the properties required to create a specific cipher instance</param> /// <param name="KeyParam">out: The KeyParams class containing a unique key, initialization vector and HMAC key</param> /// <param name="ExtensionKey">out: The random key used to encrypt the message file extension</param> /// /// <returns>The KeyId array used to identify a subkey set; set as the KeyId in a MessageHeader structure</returns> /// /// <exception cref="CryptoProcessingException">Thrown if the user has insufficient access rights to perform encryption with this key.</exception> public byte[] NextKey(out CipherDescription Description, out KeyParams KeyParam, out byte[] ExtensionKey) { if (!AccessScope.Equals(KeyScope.Creator)) throw new CryptoProcessingException("PackageFactory:NextKey", "You do not have permission to encrypt with this key!", new UnauthorizedAccessException()); try { // get the key data MemoryStream keyStream = GetKeyStream(); // get the next unused key for encryption int index = PackageKey.NextSubkey(keyStream); if (index == -1) throw new CryptoProcessingException("PackageFactory:NextKey", "The key file has expired! There are no keys left available for encryption.", new Exception()); // get the cipher description Description = _keyPackage.Description; // get the file extension key ExtensionKey = _keyPackage.ExtensionKey; // store the subkey identity, this is written into the message header to identify the subkey byte[] keyId = _keyPackage.SubKeyID[index]; // get the starting position of the keying material within the package long keyPos = PackageKey.SubKeyOffset(keyStream, keyId); // no unused keys in the package file if (keyPos == -1) throw new CryptoProcessingException("PackageFactory:NextKey", "The key file has expired! There are no keys left available for encryption.", new Exception()); // get the keying material KeyParam = GetKeySet(keyStream, _keyPackage.Description, keyPos); // mark the subkey as expired PackageKey.SubKeySetPolicy(keyStream, index, (long)PackageKeyStates.Expired); // write to file WriteKeyStream(keyStream); // return the subkey id return keyId; } catch { throw; } }
/// <summary> /// Initialize the class with a CipherDescription Structure; containing the cipher implementation details, and a <see cref="KeyParams"/> class containing the Key material. /// <para>This constructor creates and configures cryptographic instances based on the cipher description contained in a CipherDescription. /// Cipher modes, padding, and engine classes are destroyed automatically through this classes Dispose() method.</para> /// </summary> /// /// <param name="Encryption">Cipher is an encryptor</param> /// <param name="Header">A <see cref="CipherDescription"/> containing the cipher description</param> /// <param name="KeyParam">A <see cref="KeyParams"/> class containing the encryption Key material</param> /// /// <exception cref="System.ArgumentException">Thrown if an invalid <see cref="CipherDescription">CipherDescription</see> is used</exception> /// <exception cref="System.ArgumentNullException">Thrown if a null <see cref="KeyParams">KeyParams</see> is used</exception> public CompressionCipher(bool Encryption, CipherDescription Header, KeyParams KeyParam) : base(Encryption, Header, KeyParam) { _isCompression = Encryption; }
/// <summary> /// Extract a subkey set (KeyParam), a file extension key, and a CipherDescription. /// <para>Used only when calling a Decryption function to get a specific subkey /// The KeyId field corresponds with the KeyId field contained in a MessageHeader structure.</para> /// </summary> /// /// <param name="KeyId">The KeyId array used to identify a subkey set; set as the KeyId in a MessageHeader structure</param> /// <param name="Description">out: The CipherDescription structure; the properties required to create a specific cipher instance</param> /// <param name="KeyParam">out: The KeyParams class containing a unique key, initialization vector and HMAC key</param> /// <param name="ExtensionKey">out: The random key used to encrypt the message file extension</param> /// /// <exception cref="CryptoProcessingException">Thrown if the user has insufficient access rights to access this PackageKey, or the PackageKey does not contain the KeyId specified</exception> public void Extract(byte[] KeyId, out CipherDescription Description, out KeyParams KeyParam, out byte[] ExtensionKey) { if (AccessScope.Equals(KeyScope.NoAccess)) throw new CryptoProcessingException("PackageFactory:Extract", "You do not have permission to access this key!", new UnauthorizedAccessException()); try { long keyPos; int index; // get the key data MemoryStream keyStream = GetKeyStream(); // get the keying materials starting offset within the key file keyPos = PackageKey.SubKeyOffset(keyStream, KeyId); if (keyPos == -1) throw new CryptoProcessingException("PackageFactory:Extract", "This package does not contain the key file!", new ArgumentException()); // get the index index = PackageKey.IndexFromId(keyStream, KeyId); // key flagged SingleUse was used for decryption and is locked out if (PackageKey.KeyHasPolicy(_keyPackage.SubKeyPolicy[index], (long)PackageKeyStates.Locked)) throw new CryptoProcessingException("PackageFactory:Extract", "SubKey is locked. The subkey has a single use policy and was previously used to decrypt the file.", new Exception()); // key flagged PostOverwrite was used for decryption and was erased if (PackageKey.KeyHasPolicy(_keyPackage.SubKeyPolicy[index], (long)PackageKeyStates.Erased)) throw new CryptoProcessingException("PackageFactory:Extract", "SubKey is erased. The subkey has a post erase policy and was previously used to decrypt the file.", new Exception()); // get the cipher description Description = _keyPackage.Description; // get the keying material KeyParam = GetKeySet(keyStream, _keyPackage.Description, keyPos); // encrypts the file extension ExtensionKey = _keyPackage.ExtensionKey; // test flags for overwrite or single use policies if (PackageKey.KeyHasPolicy(KeyPolicy, (long)KeyPolicies.PostOverwrite)) PackageKey.SubKeySetPolicy(keyStream, index, (long)PackageKeyStates.Erased); else if (PackageKey.KeyHasPolicy(KeyPolicy, (long)KeyPolicies.SingleUse)) PackageKey.SubKeySetPolicy(keyStream, index, (long)PackageKeyStates.Locked); // post overwrite flag set, erase the subkey if (PackageKey.KeyHasPolicy(KeyPolicy, (long)KeyPolicies.PostOverwrite)) { int keySize = Description.KeySize + Description.IvSize + Description.MacSize; // overwrite the region within file Erase(keyPos, keySize); // clear this section of the key keyStream.Seek(keyPos, SeekOrigin.Begin); keyStream.Write(new byte[keySize], 0, keySize); } // write to file WriteKeyStream(keyStream); } catch { throw; } }
/// <summary> /// Create a single use key file using a <see cref="KeyParams"/> containing the key material, and a <see cref="CipherDescription"/> containing the cipher implementation details /// </summary> /// /// <param name="Description">The <see cref="CipherDescription">Cipher Description</see> containing the cipher details</param> /// <param name="KeyParam">An initialized and populated key material container</param> /// /// <exception cref="CryptoProcessingException">Thrown if a KeyParams member is null, but specified in the Header or a Header parameter does not match a KeyParams value</exception> public void Create(CipherDescription Description, KeyParams KeyParam) { if (KeyParam.Key == null) throw new CryptoProcessingException("KeyFactory:Create", "The key can not be null!", new ArgumentNullException()); if (KeyParam.Key.Length != Description.KeySize) throw new CryptoProcessingException("KeyFactory:Create", "The key parameter does not match the key size specified in the Header!", new ArgumentOutOfRangeException()); if (Description.IvSize > 0 && KeyParam.IV != null) { if (KeyParam.IV.Length != Description.IvSize) throw new CryptoProcessingException("KeyFactory:Create", "The KeyParam IV size does not align with the IVSize setting in the Header!", new ArgumentOutOfRangeException()); } if (Description.MacSize > 0) { if (KeyParam.IKM == null) throw new CryptoProcessingException("KeyFactory:Create", "Digest key is specified in the header MacSize, but is null in KeyParam!", new ArgumentNullException()); if (KeyParam.IKM.Length != Description.MacSize) throw new CryptoProcessingException("KeyFactory:Create", "Header MacSize does not align with the size of the KeyParam IKM!", new ArgumentOutOfRangeException()); } if (_keyStream == null) _keyStream = new FileStream(_keyPath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read); byte[] hdr = new CipherKey(Description).ToBytes(); _keyStream.Write(hdr, 0, hdr.Length); byte[] key = ((MemoryStream)KeyParams.Serialize(KeyParam)).ToArray(); _keyStream.Write(key, 0, key.Length); }
/// <summary> /// Initialize the class with a CipherDescription Structure; containing the cipher implementation details, and a <see cref="KeyParams"/> class containing the Key material. /// <para>This constructor creates and configures cryptographic instances based on the cipher description contained in a CipherDescription. /// Cipher modes, padding, and engines are destroyed automatically through this classes Dispose() method.</para> /// </summary> /// /// <param name="Encryption">Cipher is an encryptor</param> /// <param name="Description">A <see cref="CipherDescription"/> containing the cipher description</param> /// <param name="KeyParam">A <see cref="KeyParams"/> class containing the encryption Key material</param> /// /// <exception cref="CryptoProcessingException">Thrown if an invalid <see cref="CipherDescription">CipherDescription</see> or <see cref="KeyParams">KeyParams</see> is used</exception> public PacketCipher(bool Encryption, CipherDescription Description, KeyParams KeyParam) { if (!CipherDescription.IsValid(Description)) throw new CryptoProcessingException("PacketCipher:CTor", "The key Header is invalid!", new ArgumentException()); if (KeyParam == null) throw new CryptoProcessingException("PacketCipher:CTor", "KeyParam can not be null!", new ArgumentNullException()); _disposeEngine = true; _isEncryption = Encryption; _blockSize = Description.BlockSize; _isParallel = false; if (_isStreamCipher = IsStreamCipher((SymmetricEngines)Description.EngineType)) { _streamCipher = GetStreamEngine((SymmetricEngines)Description.EngineType, Description.RoundCount, (Digests)Description.KdfEngine); _streamCipher.Initialize(KeyParam); if (_streamCipher.GetType().Equals(typeof(Fusion))) { if (_isParallel = ((Fusion)_streamCipher).IsParallel) _blockSize = ((Fusion)_streamCipher).ParallelBlockSize; } } else { _cipherEngine = GetCipher((CipherModes)Description.CipherType, (SymmetricEngines)Description.EngineType, Description.RoundCount, Description.BlockSize, (Digests)Description.KdfEngine); _cipherEngine.Initialize(_isEncryption, KeyParam); if (_isCounterMode = _cipherEngine.GetType().Equals(typeof(CTR))) { if (_isParallel = ((CTR)_cipherEngine).IsParallel) _blockSize = ((CTR)_cipherEngine).ParallelBlockSize; } else { if (_cipherEngine.GetType().Equals(typeof(CBC))) { if (_isParallel = ((CBC)_cipherEngine).IsParallel && !((CBC)_cipherEngine).IsEncryption) _blockSize = ((CBC)_cipherEngine).ParallelBlockSize; } else if (_cipherEngine.GetType().Equals(typeof(CFB))) { if (_isParallel = ((CFB)_cipherEngine).IsParallel && !((CFB)_cipherEngine).IsEncryption) _blockSize = ((CFB)_cipherEngine).ParallelBlockSize; } } } }
/// <summary> /// Create a single use key file using automatic key material generation. /// <para>The Key, and optional IV and IKM are generated automatically using the cipher description contained in the <see cref="CipherDescription"/>. /// This overload creates keying material using the seed and digest engines specified with the <see cref="KeyGenerator"/> class</para> /// </summary> /// /// <param name="Description">The <see cref="CipherDescription">Cipher Description</see> containing the cipher implementation details</param> /// <param name="SeedEngine">The <see cref="Prngs">Random Generator</see> used to create the stage I seed material during key generation.</param> /// <param name="HashEngine">The <see cref="Digests">Digest Engine</see> used in the stage II phase of key generation.</param> /// /// <exception cref="System.ArgumentNullException">Thrown if a KeyParams member is null, but specified in the Header</exception> /// <exception cref="System.ArgumentOutOfRangeException">Thrown if a Header parameter does not match a KeyParams value</exception> public void Create(CipherDescription Description, Prngs SeedEngine = Prngs.CSPRng, Digests HashEngine = VTDev.Libraries.CEXEngine.Crypto.Enumeration.Digests.SHA512) { KeyParams keyParam; using (KeyGenerator keyGen = new KeyGenerator(SeedEngine, HashEngine)) keyParam = keyGen.GetKeyParams(Description.KeySize, Description.IvSize, Description.MacSize); Create(Description, keyParam); }
/// <summary> /// Get this is a valid header file /// </summary> /// /// <param name="Description">The stream containing a key header</param> /// /// <returns>Valid</returns> public static bool IsValid(CipherDescription Description) { // not guaranteed, but should be ok return(Description.EngineType < Enum.GetValues(typeof(SymmetricEngines)).Length << 2); }
/// <summary> /// Initialize the PackageKey structure using a Stream /// </summary> /// /// <param name="KeyStream">The Stream containing the PackageKey</param> public PackageKey(Stream KeyStream) { BinaryReader reader = new BinaryReader(KeyStream); KeyPolicy = reader.ReadInt64(); CreatedOn = reader.ReadInt64(); Authority = new KeyAuthority(KeyStream); Description = new CipherDescription(KeyStream); ExtensionKey = reader.ReadBytes(EXTKEY_SIZE); SubKeyCount = reader.ReadInt32(); SubKeyPolicy = new long[SubKeyCount]; byte[] buffer = reader.ReadBytes(SubKeyCount * KEYPOL_SIZE); Buffer.BlockCopy(buffer, 0, SubKeyPolicy, 0, buffer.Length); buffer = reader.ReadBytes(SubKeyCount * KEYID_SIZE); SubKeyID = new byte[SubKeyCount][]; for (int i = 0; i < SubKeyCount; i++) { SubKeyID[i] = new byte[KEYID_SIZE]; Buffer.BlockCopy(buffer, i * KEYID_SIZE, SubKeyID[i], 0, KEYID_SIZE); } }
/// <summary> /// Set the CipherDescription structure /// </summary> /// /// <param name="KeyStream">The stream containing a key package</param> /// <param name="Description">The CipherDescription structure</param> public static void SetCipherDescription(Stream KeyStream, CipherDescription Description) { KeyStream.Seek(DESC_SEEK, SeekOrigin.Begin); new BinaryWriter(KeyStream).Write(Description.ToBytes()); }
/// <summary> /// Test the VolumeCipher class implementation /// </summary> public static void VolumeCipherTest(string InputDirectory) { string[] paths = DirectoryTools.GetFiles(InputDirectory); // set cipher paramaters CipherDescription desc = new CipherDescription( SymmetricEngines.RDX, 32, IVSizes.V128, CipherModes.CTR, PaddingModes.X923, BlockSizes.B128, RoundCounts.R14, Digests.Keccak512, 64, Digests.Keccak512); // define the volume key VolumeKey vkey = new VolumeKey(desc, paths.Length); // key will be written to this stream MemoryStream keyStream = new MemoryStream(); // create the volume key stream using (VolumeFactory vf = new VolumeFactory(keyStream)) vf.Create(vkey); // encrypt the files in the directory using (VolumeCipher vc = new VolumeCipher(true, keyStream)) vc.Transform(paths); // decrypt the files using (VolumeCipher vc = new VolumeCipher(false, keyStream)) vc.Transform(paths); // manual inspection of files.. }
/// <remarks> /// Returns the populated KeyParams class /// </remarks> private KeyParams GetKeySet(MemoryStream KeyStream, CipherDescription Description, long Position) { KeyParams keyParam; KeyStream.Seek(Position, SeekOrigin.Begin); // create the keyparams class if (Description.MacSize > 0 && Description.IvSize > 0) { byte[] key = new byte[Description.KeySize]; byte[] iv = new byte[Description.IvSize]; byte[] ikm = new byte[Description.MacSize]; KeyStream.Read(key, 0, key.Length); KeyStream.Read(iv, 0, iv.Length); KeyStream.Read(ikm, 0, ikm.Length); keyParam = new KeyParams(key, iv, ikm); } else if (Description.IvSize > 0) { byte[] key = new byte[Description.KeySize]; byte[] iv = new byte[Description.IvSize]; KeyStream.Read(key, 0, key.Length); KeyStream.Read(iv, 0, iv.Length); keyParam = new KeyParams(key, iv); } else if (Description.MacSize > 0) { byte[] key = new byte[Description.KeySize]; byte[] ikm = new byte[Description.MacSize]; KeyStream.Read(key, 0, key.Length); KeyStream.Read(ikm, 0, ikm.Length); keyParam = new KeyParams(key, null, ikm); } else { byte[] key = new byte[Description.KeySize]; KeyStream.Read(key, 0, key.Length); keyParam = new KeyParams(key); } return keyParam; }
/// <summary> /// Creates a temporary PackageKey on disk, extracts and compares the copy /// <para>Throws an Exception on failure</</para> /// </summary> public static void PackageFactoryTest() { string path = GetTempPath(); KeyGenerator kgen = new KeyGenerator(); // populate a KeyAuthority structure KeyAuthority authority = new KeyAuthority(kgen.GetBytes(16), kgen.GetBytes(16), kgen.GetBytes(16), kgen.GetBytes(32), 0); // cipher paramaters CipherDescription desc = new CipherDescription( SymmetricEngines.RDX, 32, IVSizes.V128, CipherModes.CTR, PaddingModes.X923, BlockSizes.B128, RoundCounts.R14, Digests.Keccak512, 64, Digests.Keccak512); // create the package key PackageKey pkey = new PackageKey(authority, desc, 10); // write a key file using (PackageFactory pf = new PackageFactory(path, authority)) pf.Create(pkey); for (int i = 0; i < pkey.SubKeyCount; i++) { CipherDescription desc2; KeyParams kp1; KeyParams kp2; byte[] ext; byte[] id = pkey.SubKeyID[i]; // get at index using (FileStream stream = new FileStream(path, FileMode.Open)) kp2 = PackageKey.AtIndex(stream, i); // read the package from id using (PackageFactory pf = new PackageFactory(path, authority)) pf.Extract(id, out desc2, out kp1, out ext); // compare key material if (!Compare.AreEqual(kp1.Key, kp2.Key)) throw new Exception(); if (!Compare.AreEqual(kp1.IV, kp2.IV)) throw new Exception(); if (!Compare.AreEqual(pkey.ExtensionKey, ext)) throw new Exception(); if (!desc.Equals(desc2)) throw new Exception(); } if (File.Exists(path)) File.Delete(path); }
/// <summary> /// Initialize an empty VolumeKey structure /// </summary> /// /// <param name="Tag">The volume tag; a 32 byte field identifying this volume</param> /// <param name="Description">The cipher description</param> /// <param name="Count">The number of key/vector pairs</param> public VolumeKey(byte[] Tag, CipherDescription Description, int Count) { this.Tag = new byte[TAG_SIZE]; Array.Copy(Tag, this.Tag, Math.Min(Tag.Length, TAG_SIZE)); this.Description = Description; this.Count = Count; this.FileId = new Int32[Count]; this.State = new byte[Count]; }
/// <summary> /// Creates a temporary VolumeKey on disk, extracts and compares the copy /// <para>Throws an Exception on failure</</para> /// </summary> public static void VolumeFactoryTest() { string path = GetTempPath(); // cipher paramaters CipherDescription desc = new CipherDescription( SymmetricEngines.RDX, 32, IVSizes.V128, CipherModes.CTR, PaddingModes.X923, BlockSizes.B128, RoundCounts.R14, Digests.Keccak512, 64, Digests.Keccak512); // create the package key VolumeKey vkey = new VolumeKey(desc, 10); // add id's for (int i = 0; i < vkey.FileId.Length; i++) vkey.FileId[i] = i; // write a key file using (VolumeFactory vf = new VolumeFactory(path)) vf.Create(vkey); for (int i = 0; i < vkey.Count; i++) { CipherDescription desc2; KeyParams kp1; KeyParams kp2; using (FileStream stream = new FileStream(path, FileMode.Open)) kp1 = VolumeKey.AtIndex(stream, i); int id = vkey.FileId[i]; // read the package using (VolumeFactory vf = new VolumeFactory(path)) vf.Extract(id, out desc2, out kp2); // compare key material if (!Compare.AreEqual(kp1.Key, kp2.Key)) throw new Exception(); if (!Compare.AreEqual(kp1.IV, kp2.IV)) throw new Exception(); if (!desc.Equals(desc2)) throw new Exception(); } if (File.Exists(path)) File.Delete(path); }
/// <summary> /// Initialize an empty VolumeKey structure; generates a random key tag identifier /// </summary> /// /// <param name="Description">The cipher description</param> /// <param name="Count">The number of key/vector pairs</param> public VolumeKey(CipherDescription Description, int Count) { this.Tag = new VTDev.Libraries.CEXEngine.Crypto.Prng.CSPRng().GetBytes(32); this.Description = Description; this.Count = Count; this.FileId = new Int32[Count]; this.State = new byte[Count]; }
/// <summary> /// Initialize the VolumeKey structure using a Stream /// </summary> /// /// <param name="KeyStream">The Stream containing the VolumeKey</param> public VolumeKey(Stream KeyStream) { BinaryReader reader = new BinaryReader(KeyStream); Tag = reader.ReadBytes(TAG_SIZE); Description = new CipherDescription(KeyStream); Count = reader.ReadInt32(); FileId = new Int32[Count]; for (int i = 0; i < Count; i++) FileId[i] = reader.ReadInt32(); State = reader.ReadBytes(Count); }
/// <summary> /// A PackageKey header structure. /// </summary> /// /// <param name="Authority">The <see cref="KeyAuthority">KeyAuthority</see> structure containing the key authorization schema.</param> /// <param name="Cipher">The <see cref="CipherDescription">CipherDescription</see> structure containing a complete description of the cipher instance.</param> /// <param name="SubKeyCount">The number of Key Sets contained in this key package file.</param> /// <param name="ExtensionKey">An array of random bytes used to encrypt a message file extension. A null value auto generates this field.</param> /// /// <exception cref="CryptoProcessingException">Thrown if an invalid ExtensionKey is used</exception> public PackageKey(KeyAuthority Authority, CipherDescription Cipher, int SubKeyCount, byte[] ExtensionKey = null) { this.KeyPolicy = Authority.KeyPolicy; this.Authority = Authority; this.Description = Cipher; this.SubKeyCount = SubKeyCount; SubKeyPolicy = new long[SubKeyCount]; SubKeyID = new byte[SubKeyCount][]; // generate the subkey ids and set master policy for (int i = 0; i < SubKeyCount; i++) { SubKeyPolicy[i] = (long)Authority.KeyPolicy; SubKeyID[i] = Guid.NewGuid().ToByteArray(); } if (ExtensionKey != null) { if (ExtensionKey.Length != 16) throw new CryptoProcessingException("PackageKey:CTor", "Extension key must be exactly 16 bytes in length!", new ArgumentOutOfRangeException()); this.ExtensionKey = ExtensionKey; } else { using (CSPRng rand = new CSPRng()) this.ExtensionKey = rand.GetBytes(16); } CreatedOn = DateTime.Now.Ticks; }
/// <summary> /// Create a volume key file using a <see cref="CipherDescription"/> containing the cipher implementation details, and a key count size /// </summary> /// /// <param name="Description">The <see cref="CipherDescription">Cipher Description</see> containing the cipher details</param> /// <param name="KeyCount">The number of key sets associated with this volume key</param> /// /// <exception cref="System.IO.FileLoadException">A key file exists at the path specified</exception> /// <exception cref="System.UnauthorizedAccessException">The key file path is read only</exception> public void Create(CipherDescription Description, int KeyCount) { this.Create(new VolumeKey(Description, KeyCount)); }
/// <summary> /// Initialize the CipherKey structure using a Stream /// </summary> /// /// <param name="KeyStream">The Stream containing the CipherKey</param> public CipherKey(Stream KeyStream) { BinaryReader reader = new BinaryReader(KeyStream); Description = new CipherDescription(KeyStream); KeyID = reader.ReadBytes(KEYID_SIZE); ExtensionKey = reader.ReadBytes(EXTKEY_SIZE); }
/// <summary> /// Create a volume key file using a manual description of the cipher parameters. /// </summary> /// /// <param name="KeyCount">The number of key sets associated with this volume key</param> /// <param name="EngineType">The Cryptographic <see cref="SymmetricEngines">Engine</see> type</param> /// <param name="KeySize">The cipher Key Size in bytes</param> /// <param name="IvSize">Size of the cipher <see cref="IVSizes">Initialization Vector</see></param> /// <param name="CipherType">The type of <see cref="CipherModes">Cipher Mode</see></param> /// <param name="PaddingType">The type of cipher <see cref="PaddingModes">Padding Mode</see></param> /// <param name="BlockSize">The cipher <see cref="BlockSizes">Block Size</see></param> /// <param name="Rounds">The number of diffusion <see cref="RoundCounts">Rounds</see></param> /// <param name="KdfEngine">The <see cref="Digests">Digest</see> engine used to power the key schedule Key Derivation Function in HX and M series ciphers</param> /// <param name="MacSize">The size of the HMAC message authentication code; a zeroed parameter means authentication is not enabled with this key</param> /// <param name="MacEngine">The HMAC <see cref="Digests">Digest</see> engine used to authenticate a message file encrypted with this key</param> /// /// <exception cref="System.IO.FileLoadException">A key file exists at the path specified</exception> /// <exception cref="System.UnauthorizedAccessException">The key file path is read only</exception> public void Create(int KeyCount, SymmetricEngines EngineType, int KeySize, IVSizes IvSize, CipherModes CipherType, PaddingModes PaddingType, BlockSizes BlockSize, RoundCounts Rounds, Digests KdfEngine, int MacSize, Digests MacEngine) { CipherDescription dsc = new CipherDescription() { EngineType = (int)EngineType, KeySize = KeySize, IvSize = (int)IvSize, CipherType = (int)CipherType, PaddingType = (int)PaddingType, BlockSize = (int)BlockSize, RoundCount = (int)Rounds, KdfEngine = (int)KdfEngine, MacEngine = (int)MacEngine, MacSize = MacSize }; Create(dsc, KeyCount); }
/// <summary> /// Extract a KeyParams and CipherDescription /// </summary> /// /// <param name="Index">The index of the key set to extract</param> /// <param name="Description">The <see cref="CipherDescription"/> that receives the cipher description</param> /// <param name="KeyParam">The <see cref="KeyParams"/> container that receives the key material from the file</param> /// /// <exception cref="CryptoProcessingException">Thrown if the key file could not be found</exception> public void Extract(int Index, out CipherDescription Description, out KeyParams KeyParam) { if (!string.IsNullOrEmpty(_keyPath)) { if (!File.Exists(_keyPath)) throw new CryptoProcessingException("VolumeFactory:Extract", "The key file could not be found! Check the path.", new FileNotFoundException()); } if (_keyStream == null) _keyStream = new FileStream(_keyPath, FileMode.Open, FileAccess.Read); VolumeKey vkey = new VolumeKey(_keyStream); Description = vkey.Description; KeyParam = VolumeKey.AtIndex(_keyStream, Index); }
/// <summary> /// Get this is a valid header file /// </summary> /// /// <param name="Description">The stream containing a key header</param> /// /// <returns>Valid</returns> public static bool IsValid(CipherDescription Description) { // not guaranteed, but should be ok return (Description.EngineType < Enum.GetValues(typeof(SymmetricEngines)).Length); }