/// <summary> /// Get this is a valid header file /// </summary> /// /// <param name="Authority">The stream containing a KeyAuthority structure</param> /// /// <returns>Valid</returns> public static bool IsValid(KeyAuthority Authority) { int count = 0; for (int i = 0; i < Authority.OriginId.Length; i++) { if (Authority.OriginId[i] == (byte)0) { count++; } } return(count < 8); }
/// <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="VTDev.Libraries.CEXEngine.Crypto.Common.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> /// /// <exception cref="CryptoProcessingException">Thrown if an invalid ExtensionKey is used</exception> public PackageKey(KeyAuthority Authority, CipherDescription Cipher, int SubKeyCount) { 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(); } CreatedOn = DateTime.Now.Ticks; }
/// <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 KeyAuthority)) { return(false); } KeyAuthority other = (KeyAuthority)Obj; if (!Compare.IsEqual(DomainId, other.DomainId)) { return(false); } if (!Compare.IsEqual(OriginId, other.OriginId)) { return(false); } if (!Compare.IsEqual(TargetId, other.TargetId)) { return(false); } if (!Compare.IsEqual(PackageId, other.PackageId)) { return(false); } if (!Compare.IsEqual(PackageTag, other.PackageTag)) { return(false); } if (KeyPolicy != other.KeyPolicy) { return(false); } if (OptionFlag != other.OptionFlag) { return(false); } return(true); }
/// <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); 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 KeyAuthority structure /// </summary> /// /// <param name="KeyStream">The stream containing a key package</param> /// <param name="Authority">The CipherDescription structure</param> public static void SetKeyAuthority(Stream KeyStream, KeyAuthority Authority) { KeyStream.Seek(KEYAUT_SEEK, SeekOrigin.Begin); new BinaryWriter(KeyStream).Write(Authority.ToBytes()); }
/// <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> /// 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 key file using a <see cref="PackageKey"/> structure; containing the cipher description and operating ids and flags. /// </summary> /// /// <param name="Package">The <see cref="PackageKey">Key Header</see> containing the cipher description and operating ids and flags</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="DigestEngine">The <see cref="Digests">Digest Engine</see> used in the stage II phase of key generation.</param> /// /// <exception cref="CryptoProcessingException">Thrown if a key file exists at the path specified, the path is read only, the CipherDescription or KeyAuthority structures are invalid, or /// number of SubKeys specified is either less than 1 or more than the maximum allowed (100,000)</exception> public void Create(PackageKey Package, Prngs SeedEngine = Prngs.CSPRng, Digests DigestEngine = Digests.SHA512) { // if you are getting exceptions.. read the docs! if (File.Exists(_keyPath)) throw new CryptoProcessingException("PackageFactory:Create", "The key file exists! Can not overwrite an existing key file, choose a different path.", new FileLoadException()); if (!DirectoryTools.IsWritable(Path.GetDirectoryName(_keyPath))) throw new CryptoProcessingException("PackageFactory:Create", "The selected directory is read only! Choose a different path.", new UnauthorizedAccessException()); if (!CipherDescription.IsValid(Package.Description)) throw new CryptoProcessingException("PackageFactory:Create", "The key package cipher settings are invalid!", new FormatException()); if (!KeyAuthority.IsValid(Package.Authority)) throw new CryptoProcessingException("PackageFactory:Create", "The key package key authority settings are invalid!", new FormatException()); if (Package.SubKeyCount < 1) throw new CryptoProcessingException("PackageFactory:Create", "The key package must contain at least 1 key!", new ArgumentOutOfRangeException()); if (Package.SubKeyCount > SUBKEY_MAX) throw new CryptoProcessingException("PackageFactory:Create", String.Format("The key package can not contain more than {0} keys!", SUBKEY_MAX), new ArgumentOutOfRangeException()); // get the size of a subkey set int subKeySize = Package.Description.KeySize; if (Package.Description.IvSize > 0) subKeySize += Package.Description.IvSize; if (Package.Description.MacSize > 0) subKeySize += Package.Description.MacSize; if (subKeySize < 0) throw new CryptoProcessingException("PackageFactory:Create", "The key package cipher settings are invalid!", new Exception()); try { // store the auth struct and policy _keyOwner = Package.Authority; this.KeyPolicy = Package.KeyPolicy; // get the serialized header byte[] header = Package.ToBytes(); // size key buffer byte[] buffer = new byte[subKeySize * Package.SubKeyCount]; // generate the keying material using (KeyGenerator keyGen = new KeyGenerator(SeedEngine, DigestEngine)) keyGen.GetBytes(buffer); using (BinaryWriter keyWriter = new BinaryWriter(new FileStream(_keyPath, FileMode.Create, FileAccess.Write))) { // pre-set the size to avoid fragmentation keyWriter.BaseStream.SetLength(PackageKey.GetHeaderSize(Package) + (subKeySize * Package.SubKeyCount)); if (IsEncrypted(Package.KeyPolicy)) { // add policy flags, only part of key not encrypted keyWriter.Write(Package.KeyPolicy); // get salt, return depends on auth flag settings byte[] salt = GetSalt(); // create a buffer for encrypted data int hdrLen = header.Length - PackageKey.GetPolicyOffset(); byte[] data = new byte[buffer.Length + hdrLen]; // copy header and key material Buffer.BlockCopy(header, PackageKey.GetPolicyOffset(), data, 0, hdrLen); Buffer.BlockCopy(buffer, 0, data, hdrLen, buffer.Length); // encrypt the key and header TransformBuffer(data, salt); // write to file keyWriter.Write(data); // don't wait for gc Array.Clear(salt, 0, salt.Length); Array.Clear(data, 0, data.Length); } else { // write the keypackage header keyWriter.Write(header, 0, header.Length); // write the keying material keyWriter.Write(buffer, 0, buffer.Length); } } // cleanup Array.Clear(header, 0, header.Length); Array.Clear(buffer, 0, buffer.Length); } catch { throw; } }
/// <summary> /// Initialize this class with a key file path. /// <para>If the key exixts, permissions are tested, otherwise this path is used as the new key path and file name.</para> /// </summary> /// /// <param name="KeyPath">The fully qualified path to the key file to be read or created</param> /// <param name="Authority">The local KeyAuthority credentials structure</param> /// /// <exception cref="CryptoProcessingException">Thrown if an empty KeyPath is used</exception> public PackageFactory(string KeyPath, KeyAuthority Authority) { if (string.IsNullOrEmpty(KeyPath) || Path.GetExtension(KeyPath).Length < 1 || Path.GetFileNameWithoutExtension(KeyPath).Length < 1 || !Path.IsPathRooted(KeyPath)) throw new CryptoProcessingException("PackageFactory:Ctor", "The key path must contain a valid directory and file name!", new ArgumentException()); // store authority _keyOwner = Authority; // file path or destination _keyPath = KeyPath; if (File.Exists(_keyPath)) AccessScope = Authenticate(); }
/// <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> /// Get this is a valid header file /// </summary> /// /// <param name="Authority">The stream containing a KeyAuthority structure</param> /// /// <returns>Valid</returns> public static bool IsValid(KeyAuthority Authority) { int count = 0; for (int i = 0; i < Authority.OriginId.Length; i++) { if (Authority.OriginId[i] == (byte)0) count++; } return count < 8; }