/// <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> /// 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 PackageKey)) { return(false); } PackageKey other = (PackageKey)Obj; if (KeyPolicy != other.KeyPolicy) { return(false); } if (CreatedOn != other.CreatedOn) { return(false); } if (Authority.GetHashCode() != other.Authority.GetHashCode()) { return(false); } if (Description.GetHashCode() != other.Description.GetHashCode()) { return(false); } if (SubKeyCount != other.SubKeyCount) { return(false); } if (!Compare.IsEqual(SubKeyPolicy, other.SubKeyPolicy)) { return(false); } if (SubKeyID.Length != 0) { for (int i = 0; i < SubKeyID.Length; ++i) { if (SubKeyID[i].Length != 0) { for (int j = 0; j < SubKeyID[i].Length; ++j) { if (SubKeyID[i][j] != other.SubKeyID[i][j]) { return(false); } } } } } return(true); }
/// <summary> /// Get the key/iv associated with a file id /// </summary> /// /// <param name="KeyStream">The stream containing the PackageKey</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, byte[] Id) { // get the header PackageKey vkey = new PackageKey(KeyStream); for (int i = 0; i < vkey.SubKeyID.Length; i++) { if (vkey.SubKeyID[i] == Id) { return(AtIndex(KeyStream, i)); } } return(null); }
/// <summary> /// Test if the PackageKey contains a file id /// </summary> /// /// <param name="KeyStream">The stream containing the PackageKey</param> /// <param name="Id">The subkey id</param> /// /// <returns>Returns true if the file id is known, otherwizse false</returns> public static bool Contains(Stream KeyStream, byte[] Id) { // get the header PackageKey pkey = new PackageKey(KeyStream); for (int i = 0; i < pkey.SubKeyID.Length; i++) { if (pkey.SubKeyID[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 key id</param> /// /// <returns>Returns the index, or <c>-1</c> if not found</returns> public static int GetIndex(Stream KeyStream, byte[] Id) { // get the header PackageKey pkey = new PackageKey(KeyStream); int index = -1; for (int i = 0; i < pkey.SubKeyID.Length; i++) { if (pkey.SubKeyID[i] == Id) { return(i); } } return(index); }
/// <summary> /// Returns the number of keys in the package with the specified policy value /// </summary> /// /// <param name="KeyStream">The stream containing the VolumeKey</param> /// <param name="KeyPolicy">The key policy to search</param> /// /// <returns>The number of keys with that policy</returns> public static int KeyCount(Stream KeyStream, KeyPolicies KeyPolicy) { // get the header PackageKey pkey = new PackageKey(KeyStream); int count = 0; for (int i = 0; i < pkey.SubKeyID.Length; i++) { if (KeyHasPolicy(pkey.SubKeyPolicy[i], (long)KeyPolicy)) { count++; } } return(count); }
/// <summary> /// Get the key/iv at a given index /// </summary> /// /// <param name="KeyStream">The stream containing the PackageKey</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 PackageKey pkey = new PackageKey(KeyStream); byte[] key = new byte[pkey.Description.KeySize]; byte[] iv = new byte[pkey.Description.IvSize]; byte[] ikm = new byte[pkey.Description.MacKeySize]; int offset = GetHeaderSize(pkey) + (Index * (pkey.Description.IvSize + pkey.Description.KeySize + pkey.Description.MacKeySize)); KeyStream.Seek(offset, SeekOrigin.Begin); KeyStream.Read(key, 0, key.Length); KeyStream.Read(iv, 0, iv.Length); KeyStream.Read(ikm, 0, ikm.Length); return(new KeyParams(key, iv, ikm)); }
/// <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> /// Get the header Size in bytes /// </summary> /// /// <param name="Package">The key package structure</param> /// /// <returns>Header size</returns> public static int GetHeaderSize(PackageKey Package) { return(POLICY_SIZE + CREATE_SIZE + KEYAUT_SIZE + DESC_SIZE + KEYCNT_SIZE + (Package.SubKeyCount * (KEYPOL_SIZE + KEYID_SIZE))); }
/// <summary> /// Returns the number of keys in the package with the specified policy value /// </summary> /// /// <param name="KeyStream">The stream containing the VolumeKey</param> /// <param name="KeyPolicy">The key policy to search</param> /// /// <returns>The number of keys with that policy</returns> public static int KeyCount(Stream KeyStream, KeyPolicies KeyPolicy) { // get the header PackageKey pkey = new PackageKey(KeyStream); int count = 0; for (int i = 0; i < pkey.SubKeyID.Length; i++) { if (KeyHasPolicy(pkey.SubKeyPolicy[i], (long)KeyPolicy)) count++; } return count; }
/// <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 key id</param> /// /// <returns>Returns the index, or <c>-1</c> if not found</returns> public static int GetIndex(Stream KeyStream, byte[] Id) { // get the header PackageKey pkey = new PackageKey(KeyStream); int index = -1; for (int i = 0; i < pkey.SubKeyID.Length; i++) { if (pkey.SubKeyID[i] == Id) return i; } return index; }
/// <summary> /// Test if the PackageKey contains a file id /// </summary> /// /// <param name="KeyStream">The stream containing the PackageKey</param> /// <param name="Id">The subkey id</param> /// /// <returns>Returns true if the file id is known, otherwizse false</returns> public static bool Contains(Stream KeyStream, byte[] Id) { // get the header PackageKey pkey = new PackageKey(KeyStream); for (int i = 0; i < pkey.SubKeyID.Length; i++) { if (pkey.SubKeyID[i] == Id) return true; } return false; }
/// <summary> /// Get the key/iv at a given index /// </summary> /// /// <param name="KeyStream">The stream containing the PackageKey</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 PackageKey pkey = new PackageKey(KeyStream); byte[] key = new byte[pkey.Description.KeySize]; byte[] iv = new byte[pkey.Description.IvSize]; byte[] ikm = new byte[pkey.Description.MacSize]; int offset = GetHeaderSize(pkey) + (Index * (pkey.Description.IvSize + pkey.Description.KeySize + pkey.Description.MacSize)); KeyStream.Seek(offset, SeekOrigin.Begin); KeyStream.Read(key, 0, key.Length); KeyStream.Read(iv, 0, iv.Length); KeyStream.Read(ikm, 0, ikm.Length); return new KeyParams(key, iv, ikm); }
private bool IsEncrypted(PackageKey Package) { return HasFlag(Package.KeyPolicy, KeyPolicies.PackageAuth); }
/// <remarks> /// Returns the PackageKey structure /// </remarks> private PackageKey GetPackage() { MemoryStream keyStream = GetKeyStream(); PackageKey package = new PackageKey(keyStream); keyStream.Dispose(); return package; }
/// <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> /// Authentication tests; specific target domain or identity, passphrase, /// and export permissions within the PackageKey key policy settings are checked /// </summary> /// /// <returns>Authorized to use this key</returns> public KeyScope Authenticate() { try { // get the key headers _keyPackage = GetPackage(); // store the master policy flag KeyPolicy = _keyPackage.KeyPolicy; // did we create this key IsCreator = Compare.AreEqual(_keyOwner.OriginId, _keyPackage.Authority.OriginId); // key made by master auth, valid only if authenticated by PackageAuth, IdentityRestrict or DomainRestrict if (PackageKey.KeyHasPolicy(KeyPolicy, (long)KeyPolicies.MasterAuth)) { if (Compare.AreEqual(_keyOwner.DomainId, _keyPackage.Authority.DomainId)) { LastError = ""; return KeyScope.Creator; } else if (Compare.AreEqual(_keyOwner.PackageId, _keyPackage.Authority.PackageId)) { LastError = ""; return KeyScope.Creator; } else if (Compare.AreEqual(_keyOwner.TargetId, _keyPackage.Authority.TargetId)) { LastError = ""; return KeyScope.Creator; } } // the key targets a specific installation identity if (PackageKey.KeyHasPolicy(KeyPolicy, (long)KeyPolicies.IdentityRestrict)) { // test only if not creator if (!Compare.AreEqual(_keyOwner.OriginId, _keyPackage.Authority.OriginId)) { // owner target field is set as a target OriginId hash if (!Compare.AreEqual(_keyOwner.TargetId, _keyPackage.Authority.TargetId)) { LastError = "You are not the intendant recipient of this key! Access is denied."; return KeyScope.NoAccess; } } } if (PackageKey.KeyHasPolicy(KeyPolicy, (long)KeyPolicies.DomainRestrict)) { // the key is domain restricted if (!Compare.AreEqual(_keyOwner.DomainId, _keyPackage.Authority.DomainId)) { LastError = "Domain identification check has failed! You must be a member of the same Domain as the Creator of this key."; return KeyScope.NoAccess; } } // the key package id is an authentication passphrase hash if (PackageKey.KeyHasPolicy(KeyPolicy, (long)KeyPolicies.PackageAuth)) { if (!Compare.AreEqual(_keyOwner.PackageId, _keyPackage.Authority.PackageId)) { LastError = "Key Package authentication has failed! Access is denied."; return KeyScope.NoAccess; } } // test for volatile flag if (PackageKey.KeyHasPolicy(KeyPolicy, (long)KeyPolicies.Volatile)) { if (_keyPackage.Authority.OptionFlag != 0 && _keyPackage.Authority.OptionFlag < DateTime.Now.Ticks) { LastError = "This key has expired and can no longer be used! Access is denied."; return KeyScope.NoAccess; } } // only the key creator is allowed access if (PackageKey.KeyHasPolicy(KeyPolicy, (long)KeyPolicies.NoExport)) { if (!Compare.AreEqual(_keyOwner.OriginId, _keyPackage.Authority.OriginId)) { LastError = "Only the Creator of this key is authorized! Access is denied."; return KeyScope.NoAccess; } } LastError = ""; return IsCreator ? KeyScope.Creator : KeyScope.Operator; } catch (Exception Ex) { LastError = Ex.Message; return KeyScope.NoAccess; } }
/// <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 the header Size in bytes /// </summary> /// /// <param name="Package">The key package structure</param> /// /// <returns>Header size</returns> public static int GetHeaderSize(PackageKey Package) { return POLICY_SIZE + CREATE_SIZE + KEYAUT_SIZE + DESC_SIZE + EXTKEY_SIZE + KEYCNT_SIZE + (Package.SubKeyCount * (KEYPOL_SIZE + KEYID_SIZE)); }
/// <summary> /// Get the key/iv associated with a file id /// </summary> /// /// <param name="KeyStream">The stream containing the PackageKey</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, byte[] Id) { // get the header PackageKey vkey = new PackageKey(KeyStream); for (int i = 0; i < vkey.SubKeyID.Length; i++) { if (vkey.SubKeyID[i] == Id) return AtIndex(KeyStream, i); } return null; }
/// <summary> /// Demonstrates saving a key file using the PackageFactory class /// </summary> private void SaveKey() { try { // add the time/date expiration stamp if key policy is volatile if (HasPolicy(KeyPolicies.Volatile)) { if (dtVolatileTime.Value.Ticks > DateTime.Now.Ticks) _container.Authority.OptionFlag = dtVolatileTime.Value.Ticks; else throw new Exception("Invalid Expiry time. If a key is marked as Volatile, the expired time must be greater than the current time."); } // get the key tag description if (!string.IsNullOrEmpty(txtKeyDescription.Text)) { byte[] data = new byte[32]; byte[] tag = Encoding.ASCII.GetBytes(txtKeyDescription.Text); Array.Copy(tag, data, tag.Length < 32 ? tag.Length : 32); _container.Authority.PackageTag = data; } // get the number of subkeys to create in this package int keyCount = 1; if (!string.IsNullOrEmpty(txtSubKeyCount.Text) && txtSubKeyCount.Text != "0") int.TryParse(txtSubKeyCount.Text, out keyCount); // create a PackageKey; a key package can contain 1 or many thousands of 'subkeys'. Each subkey set // contains one group of unique random keying material; key, iv, and optional hmac key. // Each key set is used only once for encryption, guaranteeing that a unique set of values is used for every encryption cycle. PackageKey package = new PackageKey( _container.Authority, // the KeyAuthority structure _container.Description, // the CipherDescription structure keyCount, // the number of subkeys to add to this key package IdGenerator()); // the file extension encryption key // create and write the key using (PackageFactory factory = new PackageFactory(_keyFilePath, _container.Authority)) factory.Create(package); // store path _lastKeyPath = Path.GetDirectoryName(_keyFilePath); Reset(); lblStatus.Text = "The Key has been saved!"; } catch (Exception ex) { if (File.Exists(_keyFilePath)) File.Delete(_keyFilePath); string message = ex.Message == null ? "" : ex.Message; MessageBox.Show("An error occured, the key could not be created! " + message); } }