/// <summary> /// Add a new file id, and key/iv pair to the VolumeKey /// </summary> /// /// <param name="KeyStream">The stream containing the VolumeKey</param> /// <param name="Key">The key</param> /// <param name="Iv">The vector</param> /// /// <returns>Returns true if the file id is known, otherwizse false</returns> public static void Add(Stream KeyStream, byte[] Key, byte[] Iv) { using (MemoryStream keyMem = new MemoryStream()) { // get the header VolumeKey vkey = new VolumeKey(KeyStream); int offset = ID_SEEK + (vkey.Count * ID_SIZE); KeyStream.Seek(offset, SeekOrigin.Begin); int kmlen = vkey.Count * (vkey.Description.KeySize + vkey.Description.IvSize); // adjust the header params vkey.Count++; ArrayUtils.AddAt(ref vkey.FileId, vkey.FileId[vkey.FileId.Length - 1]++, vkey.Count); ArrayUtils.AddAt(ref vkey.State, (byte)0, vkey.Count); // copy header to mem vkey.ToStream().WriteTo(keyMem); byte[] data = new byte[kmlen]; // copy existing key/iv pairs KeyStream.Read(data, 0, data.Length); keyMem.Write(data, 0, data.Length); // write new keyMem.Write(Key, 0, Key.Length); keyMem.Write(Iv, 0, Iv.Length); // overwrite stream w/ new KeyStream.Seek(0, SeekOrigin.Begin); keyMem.WriteTo(KeyStream); } }
/// <summary> /// Remove a file id, and key/iv pair from the VolumeKey /// </summary> /// /// <param name="KeyStream">The stream containing the VolumeKey</param> /// <param name="Id">The file id</param> /// /// <returns>Returns true if the file id is known, otherwizse false</returns> /// /// <exception cref="CryptoProcessingException">Thrown if the Id does not exist</exception> public static void Remove(Stream KeyStream, int Id) { int index = GetIndex(KeyStream, Id); if (index == -1) { throw new CryptoProcessingException("VolumeKey:Remove", "The id does not exist!", new ArgumentException()); } using (MemoryStream keyMem = new MemoryStream()) { // get the header VolumeKey vkey = new VolumeKey(KeyStream); int offset = ID_SEEK + (vkey.Count * (ID_SIZE + STATE_SIZE)); KeyStream.Seek(offset, SeekOrigin.Begin); // adjust the count vkey.Count--; // create reduced arrays ArrayUtils.RemoveAt(ref vkey.FileId, index); ArrayUtils.RemoveAt(ref vkey.State, index); // get the key material int klen = vkey.Description.KeySize + vkey.Description.IvSize; int koff = klen * index; byte[] data = new byte[klen * vkey.Count]; KeyStream.Read(data, 0, data.Length); ArrayUtils.RemoveRange(ref data, koff, koff + klen); keyMem.Write(data, 0, data.Length); // overwrite stream w/ new key KeyStream.Seek(0, SeekOrigin.Begin); keyMem.WriteTo(KeyStream); } }
/// <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 VolumeKey)) { return(false); } VolumeKey other = (VolumeKey)Obj; if (!Compare.IsEqual(Tag, other.Tag)) { return(false); } if (Description.GetHashCode() != other.Description.GetHashCode()) { return(false); } if (Count != other.Count) { return(false); } if (!Compare.IsEqual(FileId, other.FileId)) { return(false); } if (!Compare.IsEqual(State, other.State)) { return(false); } return(true); }
/// <summary> /// Get the key/iv at a given index /// </summary> /// /// <param name="KeyStream">The stream containing the VolumeKey</param> /// <param name="Index">The index value</param> /// /// <returns>A populated KeyParams class</returns> public static KeyParams AtIndex(Stream KeyStream, int Index) { // get the header VolumeKey vkey = new VolumeKey(KeyStream); byte[] key = new byte[vkey.Description.KeySize]; byte[] iv = new byte[vkey.Description.IvSize]; int offset = ID_SEEK + (vkey.Count * (ID_SIZE + STATE_SIZE) + (Index * (vkey.Description.IvSize + vkey.Description.KeySize))); KeyStream.Seek(offset, SeekOrigin.Begin); KeyStream.Read(key, 0, key.Length); KeyStream.Read(iv, 0, iv.Length); return(new KeyParams(key, iv)); }
/// <summary> /// Test if the VolumeKey contains a file id /// </summary> /// /// <param name="KeyStream">The stream containing the VolumeKey</param> /// <param name="Id">The file id</param> /// /// <returns>Returns true if the file id is known, otherwizse false</returns> public static bool Contains(Stream KeyStream, int Id) { // get the header VolumeKey vkey = new VolumeKey(KeyStream); for (int i = 0; i < vkey.Count; i++) { if (vkey.FileId[i] == Id) { return(true); } } return(false); }
/// <summary> /// Get the key/iv associated with a file id /// </summary> /// /// <param name="KeyStream">The stream containing the VolumeKey</param> /// <param name="Id">The file id</param> /// /// <returns>A populated KeyParams class, or null if the key is not found</returns> public static KeyParams FromId(Stream KeyStream, int Id) { // get the header VolumeKey vkey = new VolumeKey(KeyStream); for (int i = 0; i < vkey.Count; i++) { if (vkey.FileId[i] == Id) { return(AtIndex(KeyStream, i)); } } return(null); }
/// <summary> /// Get the index of the next unused key/iv in the volume key /// </summary> /// /// <param name="KeyStream">The stream containing the VolumeKey</param> /// /// <returns>The index of the next available key pair</returns> public static int NextSubKey(Stream KeyStream) { // get the header VolumeKey vkey = new VolumeKey(KeyStream); int index = -1; for (int i = 0; i < vkey.Count; i++) { if (vkey.State[i] == (byte)VolumeKeyStates.Unassigned) { return(i); } } return(index); }
/// <summary> /// Get the index of the file id in the VolumeKey /// </summary> /// /// <param name="KeyStream">The stream containing the VolumeKey</param> /// <param name="Id">The file id</param> /// /// <returns>Returns the index, or <c>-1</c> if not found</returns> public static int GetIndex(Stream KeyStream, int Id) { // get the header VolumeKey vkey = new VolumeKey(KeyStream); int index = -1; for (int i = 0; i < vkey.Count; i++) { if (vkey.FileId[i] == Id) { return(i); } } return(index); }
/// <summary> /// Returns the number of keys in the volume with the specified state value /// </summary> /// /// <param name="KeyStream">The stream containing the VolumeKey</param> /// <param name="KeyState">The state to search</param> /// /// <returns>The number of keys with that state</returns> public static int KeyCount(Stream KeyStream, VolumeKeyStates KeyState = VolumeKeyStates.Unassigned) { // get the header VolumeKey vkey = new VolumeKey(KeyStream); int count = 0; for (int i = 0; i < vkey.Count; i++) { if (vkey.State[i] == (byte)KeyState) { count++; } } return(count); }
/// <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.. }
/// <summary> /// Test if the VolumeKey contains a file id /// </summary> /// /// <param name="KeyStream">The stream containing the VolumeKey</param> /// <param name="Id">The file id</param> /// /// <returns>Returns true if the file id is known, otherwizse false</returns> public static bool Contains(Stream KeyStream, int Id) { // get the header VolumeKey vkey = new VolumeKey(KeyStream); for (int i = 0; i < vkey.Count; i++) { if (vkey.FileId[i] == Id) return true; } return false; }
/// <summary> /// Get the index of the file id in the VolumeKey /// </summary> /// /// <param name="KeyStream">The stream containing the VolumeKey</param> /// <param name="Id">The file id</param> /// /// <returns>Returns the index, or <c>-1</c> if not found</returns> public static int GetIndex(Stream KeyStream, int Id) { // get the header VolumeKey vkey = new VolumeKey(KeyStream); int index = -1; for (int i = 0; i < vkey.Count; i++) { if (vkey.FileId[i] == Id) return i; } return index; }
/// <summary> /// Get the key/iv associated with a file id /// </summary> /// /// <param name="KeyStream">The stream containing the VolumeKey</param> /// <param name="Id">The file id</param> /// /// <returns>A populated KeyParams class, or null if the key is not found</returns> public static KeyParams FromId(Stream KeyStream, int Id) { // get the header VolumeKey vkey = new VolumeKey(KeyStream); for (int i = 0; i < vkey.Count; i++) { if (vkey.FileId[i] == Id) return AtIndex(KeyStream, i); } return null; }
/// <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> /// Returns the number of keys in the volume with the specified state value /// </summary> /// /// <param name="KeyStream">The stream containing the VolumeKey</param> /// <param name="KeyState">The state to search</param> /// /// <returns>The number of keys with that state</returns> public static int KeyCount(Stream KeyStream, VolumeKeyStates KeyState = VolumeKeyStates.Unassigned) { // get the header VolumeKey vkey = new VolumeKey(KeyStream); int count = 0; for (int i = 0; i < vkey.Count; i++) { if (vkey.State[i] == (byte)KeyState) count++; } return count; }
/// <summary> /// Get the key/iv at a given index /// </summary> /// /// <param name="KeyStream">The stream containing the VolumeKey</param> /// <param name="Index">The index value</param> /// /// <returns>A populated KeyParams class</returns> public static KeyParams AtIndex(Stream KeyStream, int Index) { // get the header VolumeKey vkey = new VolumeKey(KeyStream); byte[] key = new byte[vkey.Description.KeySize]; byte[] iv = new byte[vkey.Description.IvSize]; int offset = ID_SEEK + (vkey.Count * (ID_SIZE + STATE_SIZE) + (Index * (vkey.Description.IvSize + vkey.Description.KeySize))); KeyStream.Seek(offset, SeekOrigin.Begin); KeyStream.Read(key, 0, key.Length); KeyStream.Read(iv, 0, iv.Length); return new KeyParams(key, iv); }
/// <summary> /// Get the index of the next unused key/iv in the volume key /// </summary> /// /// <param name="KeyStream">The stream containing the VolumeKey</param> /// /// <returns>The index of the next available key pair</returns> public static int NextSubKey(Stream KeyStream) { // get the header VolumeKey vkey = new VolumeKey(KeyStream); int index = -1; for (int i = 0; i < vkey.Count; i++) { if (vkey.State[i] == (byte)VolumeKeyStates.Unassigned) return i; } return index; }
/// <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="KeyStream">A stream containing a <see cref="VolumeKey"/> and the keying material</param> /// /// <exception cref="CryptoProcessingException">Thrown if an invalid <see cref="VolumeKey"/> is used</exception> public VolumeCipher(bool Encryption, Stream KeyStream) { _keyStream = KeyStream; _volumeKey = new VolumeKey(KeyStream); if (!CipherDescription.IsValid(_volumeKey.Description)) throw new CryptoProcessingException("VolumeCipher:CTor", "The key Header is invalid!", new ArgumentException()); _disposeEngine = true; _isEncryption = Encryption; _blockSize = _volumeKey.Description.BlockSize; _isParallel = false; CipherDescription desc = _volumeKey.Description; if (_isStreamCipher = IsStreamCipher((SymmetricEngines)desc.EngineType)) { _streamCipher = GetStreamEngine((SymmetricEngines)desc.EngineType, desc.RoundCount, (Digests)desc.KdfEngine); if (_streamCipher.GetType().Equals(typeof(Fusion))) { if (_isParallel = ((Fusion)_streamCipher).IsParallel) _blockSize = ((Fusion)_streamCipher).ParallelBlockSize; } } else { _cipherEngine = GetCipher((CipherModes)desc.CipherType, (SymmetricEngines)desc.EngineType, desc.RoundCount, desc.BlockSize, (Digests)desc.KdfEngine); 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; } _cipherPadding = GetPadding((PaddingModes)_volumeKey.Description.PaddingType); } } }
/// <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> /// Remove a file id, and key/iv pair from the VolumeKey /// </summary> /// /// <param name="KeyStream">The stream containing the VolumeKey</param> /// <param name="Id">The file id</param> /// /// <returns>Returns true if the file id is known, otherwizse false</returns> /// /// <exception cref="CryptoProcessingException">Thrown if the Id does not exist</exception> public static void Remove(Stream KeyStream, int Id) { int index = GetIndex(KeyStream, Id); if (index == -1) throw new CryptoProcessingException("VolumeKey:Remove", "The id does not exist!", new ArgumentException()); using (MemoryStream keyMem = new MemoryStream()) { // get the header VolumeKey vkey = new VolumeKey(KeyStream); int offset = ID_SEEK + (vkey.Count * (ID_SIZE + STATE_SIZE)); KeyStream.Seek(offset, SeekOrigin.Begin); // adjust the count vkey.Count--; // create reduced arrays ArrayUtils.RemoveAt(ref vkey.FileId, index); ArrayUtils.RemoveAt(ref vkey.State, index); // get the key material int klen = vkey.Description.KeySize + vkey.Description.IvSize; int koff = klen * index; byte[] data = new byte[klen * vkey.Count]; KeyStream.Read(data, 0, data.Length); ArrayUtils.RemoveRange(ref data, koff, koff + klen); keyMem.Write(data, 0, data.Length); // overwrite stream w/ new key KeyStream.Seek(0, SeekOrigin.Begin); keyMem.WriteTo(KeyStream); } }
/// <summary> /// Create a volume key file using automatic key material generation. /// <para>The Key, and IV sets 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="Key">The <see cref="VolumeKey">VolumeKey</see> containing the cipher and key 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.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(VolumeKey Key, Prngs SeedEngine = Prngs.CSPRng, Digests HashEngine = Digests.SHA512) { int ksize = Key.Count * (Key.Description.KeySize + Key.Description.IvSize); byte[] kdata; using (KeyGenerator keyGen = new KeyGenerator(SeedEngine, HashEngine)) kdata = keyGen.GetBytes(ksize); if (_keyStream == null) _keyStream = new FileStream(_keyPath, FileMode.Create, FileAccess.Write); byte[] hdr = Key.ToBytes(); _keyStream.Write(hdr, 0, hdr.Length); _keyStream.Write(kdata, 0, kdata.Length); }
/// <summary> /// Add a new file id, and key/iv pair to the VolumeKey /// </summary> /// /// <param name="KeyStream">The stream containing the VolumeKey</param> /// <param name="Id">The file id</param> /// <param name="Key">The key</param> /// <param name="Iv">The vector</param> /// /// <returns>Returns true if the file id is known, otherwizse false</returns> public static void Add(Stream KeyStream, int Id, byte[] Key, byte[] Iv) { using (MemoryStream keyMem = new MemoryStream()) { // get the header VolumeKey vkey = new VolumeKey(KeyStream); int offset = ID_SEEK + (vkey.Count * ID_SIZE); KeyStream.Seek(offset, SeekOrigin.Begin); int kmlen = vkey.Count * (vkey.Description.KeySize + vkey.Description.IvSize); // adjust the header params vkey.Count++; ArrayUtils.AddAt(ref vkey.FileId, Id, vkey.Count); ArrayUtils.AddAt(ref vkey.State, (byte)0, vkey.Count); // copy header to mem vkey.ToStream().WriteTo(keyMem); byte[] data = new byte[kmlen]; // copy existing key/iv pairs KeyStream.Read(data, 0, data.Length); keyMem.Write(data, 0, data.Length); // write new keyMem.Write(Key, 0, Key.Length); keyMem.Write(Iv, 0, Iv.Length); // overwrite stream w/ new KeyStream.Seek(0, SeekOrigin.Begin); keyMem.WriteTo(KeyStream); } }