/// <summary> /// TODO /// </summary> /// <param name="request"></param> /// <param name="password"></param> /// <param name="desiredKeyDerivationMilliseconds"></param> public void EncryptDataWithHeader(RequestStateRecord request, SecureString password, int desiredKeyDerivationMilliseconds) { if (request.Contract.InstanceKeyContract == null) { throw new ArgumentNullException(nameof(request)); } ((IProgress <int>) this._progress)?.Report(0); password.MakeReadOnly(); var salt = new byte[request.Contract.InstanceKeyContract.Value.SaltLengthBytes]; var iv = new byte[request.Contract.TransformationContract.InitializationVectorSizeBytes]; var rng = new RNGCryptoServiceProvider(); try { rng.GetBytes(salt); rng.GetBytes(iv); } catch (CryptographicException exception) { FileStatics.WriteToLogFile(exception); MessageBox.Show( "There was an error generating secure random numbers. Please try again - check log file for more details"); } var performanceDerivative = new PerformanceDerivative(request.Contract.InstanceKeyContract.Value.PerformanceDerivative); ((IProgress <int>) this._progress)?.Report(25); // Get the password if (password.Length == 0) { MessageBox.Show("You must enter a password"); ((IProgress <int>) this._progress)?.Report(0); return; } #if TRACE if (password.Length < App.This.CurrentSettings.MinPasswordLength) { MessageBox.Show("Password too short"); ((IProgress <int>)_progress)?.Report(0); return; } #endif GCHandle byteHandle = SecureStringConverter.SecureStringToKeyDerive(password, salt, performanceDerivative, request.Contract.InstanceKeyContract.Value.KeyAlgorithm, out KeyDerive keyDevice); ((IProgress <int>) this._progress)?.Report(35); HMAC hmacAlg = null; if (request.Contract.HmacContract != null) { // Create the algorithm using reflection hmacAlg = (HMAC)Activator.CreateInstance(request.Contract.HmacContract.Value.HashAlgorithm); } Aes aesAlgorithm = new AesCng { BlockSize = (int)request.Contract.TransformationContract.BlockSize, KeySize = (int)request.Contract.TransformationContract.KeySize, Mode = request.Contract.TransformationContract.CipherMode, Padding = request.Contract.TransformationContract.PaddingMode }; var @params = new object[] { 1024 * 1024 * 1024, aesAlgorithm }; var encryptor = (SymmetricCryptoManager)Activator.CreateInstance(request.Contract.TransformationContract.CryptoManager, @params); byte[] key = keyDevice.GetBytes((int)request.Contract.TransformationContract.KeySize / 8); Externals.ZeroMemory(byteHandle.AddrOfPinnedObject(), ((byte[])byteHandle.Target).Length); byteHandle.Free(); // Create a handle to the key to allow control of it GCHandle keyHandle = GCHandle.Alloc(key, GCHandleType.Pinned); // Encrypt the data to a temporary file encryptor.EncryptFileBytes(this._filePath, App.This.DataTempFile, key, iv); ((IProgress <int>) this._progress)?.Report(90); byte[] hash = null; if (request.Contract.HmacContract != null) { // Create the signature derived from the encrypted data and key byte[] signature = MessageAuthenticator.CreateHmac(App.This.DataTempFile, key, hmacAlg); // Set the signature correctly in the CryptographicRepresentative object hash = signature; } HmacRepresentative?hmac = request.Contract.HmacContract.HasValue ? new HmacRepresentative(request.Contract.HmacContract.Value.HashAlgorithm, hash) : (HmacRepresentative?)null; KeyRepresentative?keyRepresentative = new KeyRepresentative ( request.Contract.InstanceKeyContract.Value.KeyAlgorithm, request.Contract.InstanceKeyContract.Value.PerformanceDerivative, salt ); // Delete the key from memory for security Externals.ZeroMemory(keyHandle.AddrOfPinnedObject(), key.Length); keyHandle.Free(); var cryptographicInfo = new SymmetricCryptographicRepresentative ( new TransformationRepresentative ( request.Contract.TransformationContract.CryptoManager, iv, request.Contract.TransformationContract.CipherMode, request.Contract.TransformationContract.PaddingMode, request.Contract.TransformationContract.KeySize, request.Contract.TransformationContract.BlockSize ), keyRepresentative, hmac ); // Write the CryptographicRepresentative object to a file cryptographicInfo.WriteHeaderToFile(this._filePath); ((IProgress <int>) this._progress)?.Report(98); FileStatics.AppendToFile(this._filePath, App.This.DataTempFile); ((IProgress <int>) this._progress)?.Report(100); }
/// <summary> /// /// </summary> /// <param name="cryptographicRepresentative"></param> /// <param name="password"></param> /// TODO decompose public void DecryptDataWithHeader(SymmetricCryptographicRepresentative cryptographicRepresentative, SecureString password) { if (cryptographicRepresentative == null) { throw new ArgumentNullException(nameof(cryptographicRepresentative)); } if (cryptographicRepresentative.InstanceKeyCreator == null) { throw new ArgumentNullException(nameof(cryptographicRepresentative.InstanceKeyCreator)); } ((IProgress <int>) this._progress)?.Report(0); password.MakeReadOnly(); var performanceDerivative = new PerformanceDerivative(cryptographicRepresentative.InstanceKeyCreator.Value.PerformanceDerivative); GCHandle byteHandle = SecureStringConverter.SecureStringToKeyDerive(password, cryptographicRepresentative.InstanceKeyCreator.Value.Salt, performanceDerivative, cryptographicRepresentative.InstanceKeyCreator.Value.KeyAlgorithm, out KeyDerive keyDevice); ((IProgress <int>) this._progress)?.Report(10); HMAC hmacAlg = null; if (cryptographicRepresentative.HmacRepresentative != null) { hmacAlg = (HMAC)Activator.CreateInstance(cryptographicRepresentative.HmacRepresentative.Value.HashAlgorithm); } var @params = new object[] { 1024 * 1024 * 8, new AesCng { BlockSize = (int)cryptographicRepresentative.TransformationModeInfo.BlockSize, KeySize = (int)cryptographicRepresentative.TransformationModeInfo.KeySize, Mode = cryptographicRepresentative.TransformationModeInfo.CipherMode, Padding = cryptographicRepresentative.TransformationModeInfo.PaddingMode } }; var decryptor = (SymmetricCryptoManager)Activator.CreateInstance(cryptographicRepresentative.TransformationModeInfo.CryptoManager, @params); FileStatics.RemovePrependData(this._filePath, App.This.HeaderLessTempFile, cryptographicRepresentative.HeaderLength); ((IProgress <int>) this._progress)?.Report(20); byte[] key = keyDevice.GetBytes((int)cryptographicRepresentative.TransformationModeInfo.KeySize / 8); Externals.ZeroMemory(byteHandle.AddrOfPinnedObject(), ((byte[])byteHandle.Target).Length); byteHandle.Free(); GCHandle keyHandle = GCHandle.Alloc(key, GCHandleType.Pinned); var isVerified = false; if (cryptographicRepresentative.HmacRepresentative != null) { // Check if the file and key make the same HMAC isVerified = MessageAuthenticator.VerifyHmac(App.This.HeaderLessTempFile, key, cryptographicRepresentative.HmacRepresentative.Value.HashBytes, hmacAlg); } ((IProgress <int>) this._progress)?.Report(35); // If that didn't succeed, the file has been tampered with if (cryptographicRepresentative.HmacRepresentative != null && !isVerified) { throw new UnverifiableDataException("File could not be verified - may have been tampered, or the password is incorrect"); } // Try decrypting the remaining data try { decryptor.DecryptFileBytes(App.This.HeaderLessTempFile, App.This.DataTempFile, key, cryptographicRepresentative.TransformationModeInfo.InitializationVector); // Move the file to the original file location File.Copy(App.This.DataTempFile, this._filePath, true); ((IProgress <int>) this._progress)?.Report(100); } finally { // Delete the key from memory for security Externals.ZeroMemory(keyHandle.AddrOfPinnedObject(), key.Length); keyHandle.Free(); } }