Compressed DecryptCommon(CipherV2 cipherV2, KeyMaterial64 keyMaterial64, LongRunningOperationContext context) { if (context == null) { context = new LongRunningOperation(progress => { }, () => { }).Context; } Guard.NotNull(new object[] { cipherV2, keyMaterial64 }); EnsurePlatform(); InputDerivedKey32 inputDerivedKey = cipherV2.RoundsExponent.Value == RoundsExponent.DontMakeRounds ? CreateDerivedKeyWithSHA256(cipherV2.IV16, keyMaterial64) : CreatePasswordDerivedKeyWithBCrypt(cipherV2.IV16, keyMaterial64, cipherV2.RoundsExponent, context); XDSSecAPIInternal.IVCache ivCache = cipherV2.RoundsExponent.Value == RoundsExponent.DontMakeRounds ? null : this._internal.CreateIVTable(cipherV2.IV16, cipherV2.RoundsExponent.Value); RandomKey32 randomKey = this._internal.AESDecryptRandomKeyWithPasswordDerivedKey(cipherV2, inputDerivedKey, ivCache, context); MAC16 decryptedMAC = this._internal.AESDecryptMAC(cipherV2, randomKey, ivCache, context); MAC16 actualMAC = CreateMAC(cipherV2, context); if (!actualMAC.GetBytes().SequenceEqual(decryptedMAC.GetBytes())) { throw new Exception(LocalizableStrings.MsgPasswordError); } PaddedData paddedData = this._internal.AESDecryptMessage(cipherV2, cipherV2.IV16, randomKey, ivCache, context); Compressed compressed = this._internal.RemovePadding(paddedData); return(compressed); }
InputDerivedKey32 CreatePasswordDerivedKeyWithBCrypt(IV16 iv, KeyMaterial64 keyMaterial64, RoundsExponent roundsExponent, LongRunningOperationContext context) { var leftSHA512 = new byte[32]; var rightSHA512 = new byte[32]; Buffer.BlockCopy(keyMaterial64.GetBytes(), 0, leftSHA512, 0, 32); Buffer.BlockCopy(keyMaterial64.GetBytes(), 32, rightSHA512, 0, 32); context.EncryptionProgress.Message = LocalizableStrings.MsgProcessingKey; // Compute the left side on a ThreadPool thread var task = Task.Run(() => BCrypt.CreateHash(iv, leftSHA512, roundsExponent.Value, context)); // Compute the right side after dispatching the work for the right side BCrypt24 rightBCrypt = BCrypt.CreateHash(iv, rightSHA512, roundsExponent.Value, context); // Wait for the left side result task.Wait(context.CancellationToken); // Use the results var combinedHashes = ByteArrays.Concatenate(keyMaterial64.GetBytes(), task.Result.GetBytes(), rightBCrypt.GetBytes()); Debug.Assert(combinedHashes.Length == 64 + 24 + 24); var condensedHash = this._platform.ComputeSHA256(combinedHashes); return(new InputDerivedKey32(condensedHash)); }
public static CipherV2 DissectVisualCryptText(string visualCryptText, LongRunningOperationContext context) { try { var visualCrypt = WhiteListVisualCryptCharacters(visualCryptText, context); if (!visualCrypt.StartsWith(VisualCryptSlashText, StringComparison.OrdinalIgnoreCase)) { throw CommonFormatException("The prefix '{0}' is missing.".FormatInvariant(VisualCryptSlashText)); } var visualCryptTextV2Base64 = visualCrypt.Remove(0, VisualCryptSlashText.Length).Replace('$', '/'); var visualCryptTextV2Bytes = Base64Encoder.DecodeBase64StringToBinary(visualCryptTextV2Base64); return(DissectBytesToCipherV2(visualCryptTextV2Bytes)); } catch (Exception e) { if (e.Message.StartsWith(LocalizableStrings.MsgFormatError)) { throw; } throw CommonFormatException(e.Message); } }
public static CipherV2 DissectVisualCryptBytes(byte[] visualCryptBytes, LongRunningOperationContext context) { if (visualCryptBytes == null) { throw new ArgumentNullException(nameof(visualCryptBytes)); } return(DissectBytesToCipherV2(visualCryptBytes)); }
public static CipherV2 DissectXDSSecBytes(byte[] xdsSecBytes, LongRunningOperationContext context) { if (xdsSecBytes == null) { throw new ArgumentNullException(nameof(xdsSecBytes)); } return(DissectBytesToCipherV2(xdsSecBytes)); }
CancellationToken _cancellationToken; // this is a struct BCrypt(LongRunningOperationContext context) { if (context == null) { throw new ArgumentNullException("context"); } this._encryptionProgress = context.EncryptionProgress; this._cancellationToken = context.CancellationToken; }
/// <summary>'Hash a password using the OpenBSD bcrypt scheme'. Adapted for XDSSec.</summary> /// <exception cref="ArgumentException">Thrown when one or more arguments have unsupported or /// illegal values.</exception> /// <param name="data">The data to hash.</param> /// <param name="iv16">The salt to hash with.</param> /// <param name="logRounds">Between [4..31].</param> /// <param name="context">Object for encryptionProgress indicator and cancelation</param> /// <returns>The hash.</returns> public static BCrypt24 CreateHash(IV16 iv16, byte[] data, byte logRounds, LongRunningOperationContext context) { Guard.NotNull(new object[] { iv16, data, context }); if (logRounds < 4 || logRounds > 31) { throw new ArgumentOutOfRangeException(nameof(logRounds), logRounds, "logRounds must be between 4 and 31 (inclusive)"); } var hash = new BCrypt(context).CryptRaw(data, iv16.GetBytes(), logRounds); return(new BCrypt24(hash)); }
static string WhiteListVisualCryptCharacters(string visualCryptBase64, LongRunningOperationContext context) { var sb = new StringBuilder(); foreach (var c in visualCryptBase64) { context.CancellationToken.ThrowIfCancellationRequested(); if (WhiteList.Contains(c)) { sb.Append(c); } } return(sb.ToString()); }
public Response <CipherV2> DecodeXDSSec(string xdsSecText, LongRunningOperationContext context) // should the parameter type be XDSSecText? { var response = new Response <CipherV2>(); try { Guard.NotNull(xdsSecText); EnsurePlatform(); response.Result = XDSSecFormatter.DissectXDSSecText(xdsSecText, context); response.SetSuccess(); } catch (Exception e) { response.SetError(e); } return(response); }
public Response <CipherV2> BinaryDecodeXDSSec(byte[] xdsSecBytes, LongRunningOperationContext context) { var response = new Response <CipherV2>(); try { Guard.NotNull(xdsSecBytes); EnsurePlatform(); context?.CancellationToken.ThrowIfCancellationRequested(); response.Result = XDSSecFormatter.DissectXDSSecBytes(xdsSecBytes, context); response.SetSuccess(); } catch (Exception e) { response.SetError(e); } return(response); }
public Response <byte[]> BinaryEncodeXDSSec(CipherV2 cipherV2, LongRunningOperationContext context) { var response = new Response <byte[]>(); try { Guard.NotNull(cipherV2); EnsurePlatform(); context?.CancellationToken.ThrowIfCancellationRequested(); response.Result = XDSSecFormatter.CreateBinary(cipherV2); response.SetSuccess(); } catch (Exception e) { response.SetError(e); } return(response); }
MAC16 CreateMAC(CipherV2 cipherV2, LongRunningOperationContext context) { // Create the MAC only for items that, while decrypting, have not been used up to this point but do include the version. var securables = ByteArrays.Concatenate(cipherV2.MessageCipher.GetBytes(), new[] { cipherV2.PlaintextPadding.Value }, new[] { CipherV2.Version }); // See e.g. http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf Chapter 7 for hash truncation. byte[] truncatedHash = new byte[16]; if (cipherV2.RoundsExponent.Value == RoundsExponent.DontMakeRounds) { var sha256 = this._platform.ComputeSHA256(securables); Buffer.BlockCopy(sha256, 0, truncatedHash, 0, 16); } else { context.EncryptionProgress.Message = LocalizableStrings.MsgCalculatingMAC; var bCrypt24 = BCrypt.CreateHash(cipherV2.IV16, securables, cipherV2.RoundsExponent.Value, context); Buffer.BlockCopy(bCrypt24.GetBytes(), 0, truncatedHash, 0, 16); } return(new MAC16(truncatedHash)); }
public Response <CipherV2> Encrypt(Cleartext cleartext, KeyMaterial64 keyMaterial64, RoundsExponent roundsExponent, LongRunningOperationContext context) { var response = new Response <CipherV2>(); try { Guard.NotNull(new object[] { cleartext, keyMaterial64, roundsExponent }); EnsurePlatform(); Compressed compressed = this._internal.Compress(cleartext); var cipherV2 = EncryptCommon(keyMaterial64, roundsExponent, context, compressed); response.Result = cipherV2; response.SetSuccess(); } catch (Exception e) { response.SetError(e); } return(response); }
async Task EncryptAndSaveDeviceVaultKeyAsync(KeyMaterial64 masterRandomKey, KeyMaterial64 masterPassphraseKeyMaterial, LongRunningOperationContext context) { context.EncryptionProgress.Message = "Encrypting master random key"; context.EncryptionProgress.Report(context.EncryptionProgress); CipherV2 encryptedMasterRandomKey = this.xdsCryptoService.BinaryEncrypt(new Clearbytes(masterRandomKey.GetBytes()), masterPassphraseKeyMaterial, new RoundsExponent(10), context).Result; byte[] encryptedMasterRandomKeyBytes = this.xdsCryptoService.BinaryEncodeXDSSec(encryptedMasterRandomKey, context).Result; await this.repo.WriteSpecialFile(MasterKeyFilename, encryptedMasterRandomKeyBytes); }
/// <summary> /// Creates, encrypts and saves the master random key during the onboarding process. /// </summary> /// <param name="newMasterPassphrase">The newly chosen master passphrase.</param> /// <param name="masterKey">The master random key material, including collected user random.</param> /// <param name="context"></param> /// <returns></returns> public async Task InitDeviceVaultKeyAsync(string newMasterPassphrase, byte[] masterKey, LongRunningOperationContext context) { KeyMaterial64 masterPassphraseKeyMaterial = CreateKeyMaterialFromPassphrase(newMasterPassphrase); byte[] deviceVaultKey = new byte[64]; Buffer.BlockCopy(masterKey, 64, deviceVaultKey, 0, 64); // use the second part, so that we do not use the wallet seed material. deviceVaultKey = this.xdsCryptoService.ComputeSHA512(deviceVaultKey); // hash it, because we have a new specific purpose and do not want key reuse. KeyMaterial64 deviceVaultKeyMaterial = new KeyMaterial64(deviceVaultKey); this.xdsCryptoService.SymmetricKeyRepository.SetDeviceVaultRandomKey(deviceVaultKeyMaterial); await Task.Run(async() => { await EncryptAndSaveDeviceVaultKeyAsync(deviceVaultKeyMaterial, masterPassphraseKeyMaterial, context); }); }
public void AESEncryptMessageWithRandomKey(PaddedData paddedData, RandomKey32 randomKey, CipherV2 cipherV2, IVCache ivCache, LongRunningOperationContext context) { Guard.NotNull(new object[] { paddedData, randomKey, cipherV2, context }); cipherV2.PlaintextPadding = paddedData.PlaintextPadding; if (cipherV2.RoundsExponent.Value == RoundsExponent.DontMakeRounds) { Debug.Assert(ivCache == null); cipherV2.MessageCipher = new MessageCipher(this._platform.ComputeAESRound(AESDir.Encrypt, cipherV2.IV16.GetBytes(), paddedData.GetBytes(), randomKey.GetBytes())); } else { context.EncryptionProgress.Message = LocalizableStrings.MsgEncryptingMessage; cipherV2.MessageCipher = new MessageCipher(ComputeAESWithRounds(AESDir.Encrypt, cipherV2.IV16, paddedData.GetBytes(), randomKey.GetBytes(), cipherV2.RoundsExponent.Value, ivCache, context)); } }
public void AESEncryptRandomKeyWithInputDerivedKey(InputDerivedKey32 inputDerivedKey, RandomKey32 randomKey, CipherV2 cipherV2, IVCache ivCache, LongRunningOperationContext context) { Guard.NotNull(new object[] { inputDerivedKey, randomKey, cipherV2, context }); if (cipherV2.RoundsExponent.Value == RoundsExponent.DontMakeRounds) { Debug.Assert(ivCache == null); cipherV2.RandomKeyCipher32 = new RandomKeyCipher32(this._platform.ComputeAESRound(AESDir.Encrypt, cipherV2.IV16.GetBytes(), randomKey.GetBytes(), inputDerivedKey.GetBytes())); } else { context.EncryptionProgress.Message = LocalizableStrings.MsgEncryptingRandomKey; cipherV2.RandomKeyCipher32 = new RandomKeyCipher32(ComputeAESWithRounds(AESDir.Encrypt, cipherV2.IV16, randomKey.GetBytes(), inputDerivedKey.GetBytes(), cipherV2.RoundsExponent.Value, ivCache, context)); } }
public PaddedData AESDecryptMessage(CipherV2 cipherV2, IV16 iv16, RandomKey32 randomKey, IVCache ivCache, LongRunningOperationContext context) { Guard.NotNull(new object[] { cipherV2, iv16, randomKey, context }); byte[] paddedDataBytes; if (cipherV2.RoundsExponent.Value == RoundsExponent.DontMakeRounds) { paddedDataBytes = this._platform.ComputeAESRound(AESDir.Decrpyt, cipherV2.IV16.GetBytes(), cipherV2.MessageCipher.GetBytes(), randomKey.GetBytes()); } else { context.EncryptionProgress.Message = LocalizableStrings.MsgDecryptingMessage; paddedDataBytes = ComputeAESWithRounds(AESDir.Decrpyt, cipherV2.IV16, cipherV2.MessageCipher.GetBytes(), randomKey.GetBytes(), cipherV2.RoundsExponent.Value, ivCache, context); } return(new PaddedData(paddedDataBytes, cipherV2.PlaintextPadding)); }
public RandomKey32 AESDecryptRandomKeyWithPasswordDerivedKey(CipherV2 cipherV2, InputDerivedKey32 inputDerivedKey, IVCache ivCache, LongRunningOperationContext context) { Guard.NotNull(new object[] { cipherV2, inputDerivedKey, context }); byte[] randomKeyBytes; if (cipherV2.RoundsExponent.Value == RoundsExponent.DontMakeRounds) { randomKeyBytes = this._platform.ComputeAESRound(AESDir.Decrpyt, cipherV2.IV16.GetBytes(), cipherV2.RandomKeyCipher32.GetBytes(), inputDerivedKey.GetBytes()); } else { context.EncryptionProgress.Message = LocalizableStrings.MsgDecryptingRandomKey; randomKeyBytes = ComputeAESWithRounds(AESDir.Decrpyt, cipherV2.IV16, cipherV2.RandomKeyCipher32.GetBytes(), inputDerivedKey.GetBytes(), cipherV2.RoundsExponent.Value, ivCache, context); } return(new RandomKey32(randomKeyBytes)); }
public MAC16 AESDecryptMAC(CipherV2 cipherV2, RandomKey32 randomKey, IVCache ivCache, LongRunningOperationContext context) { Guard.NotNull(new object[] { cipherV2, randomKey, context }); byte[] macBytes; if (cipherV2.RoundsExponent.Value == RoundsExponent.DontMakeRounds) { macBytes = this._platform.ComputeAESRound(AESDir.Decrpyt, cipherV2.IV16.GetBytes(), cipherV2.MACCipher16.GetBytes(), randomKey.GetBytes()); } else { context.EncryptionProgress.Message = LocalizableStrings.MsgDecryptingMAC; macBytes = ComputeAESWithRounds(AESDir.Decrpyt, cipherV2.IV16, cipherV2.MACCipher16.GetBytes(), randomKey.GetBytes(), cipherV2.RoundsExponent.Value, ivCache, context); } return(new MAC16(macBytes)); }
byte[] ComputeAESWithRounds(AESDir aesDir, IV16 iv, byte[] dataBytes, byte[] keyBytes, byte roundsExp, IVCache ivCache, LongRunningOperationContext context) { Guard.NotNull(new object[] { aesDir, iv, dataBytes, keyBytes, roundsExp, ivCache, context }); var rounds = 1u << roundsExp; var roundsToGo = rounds; byte[] inputData = dataBytes; byte[] aesResult = null; while (roundsToGo > 0) { byte[] currentIV = aesDir == AESDir.Encrypt ? ivCache.IVTable.Item2[roundsToGo - 1] : ivCache.IVTable.Item2[ivCache.IVTable.Item2.Length - roundsToGo]; aesResult = this._platform.ComputeAESRound(aesDir, currentIV, inputData, keyBytes); inputData = aesResult; roundsToGo--; // decrement before calculating the percentage or we'll be stuck at 99% // START encryptionProgress / Cancellation context.CancellationToken.ThrowIfCancellationRequested(); decimal progressValue = (rounds - roundsToGo) / (decimal)(rounds); context.EncryptionProgress.Percent = (int)(progressValue * 100m); context.EncryptionProgress.Report(context.EncryptionProgress); // END encryptionProgress } return(aesResult); }
public void AESEncryptMACWithRandomKey(CipherV2 cipherV2, MAC16 mac, RandomKey32 randomKey, IVCache ivCache, LongRunningOperationContext context) { Guard.NotNull(new object[] { cipherV2, mac, randomKey, context }); if (cipherV2.RoundsExponent.Value == RoundsExponent.DontMakeRounds) { Debug.Assert(ivCache == null); cipherV2.MACCipher16 = new MACCipher16(this._platform.ComputeAESRound(AESDir.Encrypt, cipherV2.IV16.GetBytes(), mac.GetBytes(), randomKey.GetBytes())); } else { context.EncryptionProgress.Message = LocalizableStrings.MsgEncryptingMAC; cipherV2.MACCipher16 = new MACCipher16(ComputeAESWithRounds(AESDir.Encrypt, cipherV2.IV16, mac.GetBytes(), randomKey.GetBytes(), cipherV2.RoundsExponent.Value, ivCache, context)); } }
CipherV2 EncryptCommon(KeyMaterial64 keyMaterial64, RoundsExponent roundsExponent, LongRunningOperationContext context, Compressed compressed) { if (context == null) { context = new LongRunningOperation(progress => { }, () => { }).Context; } if (this._log) { Debug.WriteLine("KeyMaterial64:"); Debug.WriteLine(keyMaterial64.GetBytes().ToHexView(false)); } if (this._log) { Debug.WriteLine("Compressed:"); Debug.WriteLine(compressed.GetBytes().ToHexView(false)); } PaddedData paddedData = this._internal.ApplyRandomPadding(compressed); if (this._log) { Debug.WriteLine("PaddedData:"); Debug.WriteLine(paddedData.GetBytes().ToHexView(false)); Debug.WriteLine("PlainTextPadding:"); Debug.WriteLine(paddedData.PlaintextPadding); } IV16 iv = new IV16(this._platform.GenerateRandomBytes(16)); if (this._log) { Debug.WriteLine("IV16:"); Debug.WriteLine(iv.GetBytes().ToHexView(false)); } InputDerivedKey32 inputDerivedKey = roundsExponent.Value == RoundsExponent.DontMakeRounds ? CreateDerivedKeyWithSHA256(iv, keyMaterial64) : CreatePasswordDerivedKeyWithBCrypt(iv, keyMaterial64, roundsExponent, context); if (this._log) { Debug.WriteLine("InputDerivedKey32:"); Debug.WriteLine(inputDerivedKey.GetBytes().ToHexView(false)); } RandomKey32 randomKey = new RandomKey32(this._platform.GenerateRandomBytes(32)); if (this._log) { Debug.WriteLine("RandomKey32:"); Debug.WriteLine(randomKey.GetBytes().ToHexView(false)); } XDSSecAPIInternal.IVCache ivCache = roundsExponent.Value == RoundsExponent.DontMakeRounds ? null : this._internal.CreateIVTable(iv, roundsExponent.Value); var cipherV2 = new CipherV2 { RoundsExponent = roundsExponent, IV16 = iv }; this._internal.AESEncryptRandomKeyWithInputDerivedKey(inputDerivedKey, randomKey, cipherV2, ivCache, context); if (this._log) { Debug.WriteLine("RandomKeyCipher32:"); Debug.WriteLine(cipherV2.RandomKeyCipher32.GetBytes().ToHexView(false)); } this._internal.AESEncryptMessageWithRandomKey(paddedData, randomKey, cipherV2, ivCache, context); if (this._log) { Debug.WriteLine("MessageCipher:"); Debug.WriteLine(cipherV2.MessageCipher.GetBytes().ToHexView(false)); } MAC16 mac = CreateMAC(cipherV2, context); if (this._log) { Debug.WriteLine("MAC16:"); Debug.WriteLine(mac.GetBytes().ToHexView(false)); } this._internal.AESEncryptMACWithRandomKey(cipherV2, mac, randomKey, ivCache, context); if (this._log) { Debug.WriteLine("MACCipher16:"); Debug.WriteLine(cipherV2.MACCipher16.GetBytes().ToHexView(false)); } return(cipherV2); }
public byte[] DefaultDecrypt(byte[] cipherTextBytes, KeyMaterial64 keyMaterial64, LongRunningOperationContext context = null) { CipherV2 cipherV2 = XDSSecFormatter.DissectXDSSecBytes(cipherTextBytes, context); var binaryDecryptResponse = BinaryDecrypt(cipherV2, keyMaterial64, context); if (!binaryDecryptResponse.IsSuccess) { throw new Exception(binaryDecryptResponse.Error); } return(binaryDecryptResponse.Result.GetBytes()); }
/// <summary> /// Loads the key file and tries to decrypt the master random key. Only if successful, it also sets the decrypted master random key in SymmetricKeyRepository. /// Then, Response.Success is true. Therefore, this method can also be used to check if the master password is correct. If it is incorrect, the method does nothing and /// Response.Success is false. /// </summary> /// <param name="unprunedUtf16LeMasterPassword">the master password</param> /// <param name="context">Progress object</param> public async Task TryLoadDecryptAndSetMasterRandomKeyAsync(string unprunedUtf16LeMasterPassword, LongRunningOperationContext context) { KeyMaterial64 masterPasswordHash = CreateKeyMaterialFromPassphrase(unprunedUtf16LeMasterPassword); byte[] encryptedRandomMasterKey = await this.repo.LoadSpecialFile(MasterKeyFilename); byte[] decryptedMasterRandomKey = this.xdsCryptoService.DefaultDecrypt(encryptedRandomMasterKey, masterPasswordHash, context); this.xdsCryptoService.SymmetricKeyRepository.SetDeviceVaultRandomKey(new KeyMaterial64(decryptedMasterRandomKey)); }
public Response <Clearbytes> BinaryDecrypt(CipherV2 cipherV2, KeyMaterial64 keyMaterial64, LongRunningOperationContext context) { var response = new Response <Clearbytes>(); try { Compressed compressed = DecryptCommon(cipherV2, keyMaterial64, context); Clearbytes cleartext = this._internal.DecompressBytes(compressed); response.Result = cleartext; response.SetSuccess(); } catch (Exception e) { response.SetError(e); } return(response); }