public void XChaCha20Poly1305CheckTestVector() { byte[] message = HexToBytes(@"4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f66202739393a204966204920636f756c64206f6666657220796f75206f6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73637265656e20776f756c642062652069742e"); byte[] key = HexToBytes(@"808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f"); byte[] nonce = HexToBytes(@"07000000404142434445464748494a4b0000000000000000"); byte[] expectedCipher = HexToBytes(@"453c0693a7407f04ff4c56aedb17a3c0a1afff01174930fc22287c33dbcf0ac8b89ad929530a1bb3ab5e69f24c7f6070c8f840c9abb4f69fbfc8a7ff5126faeebbb55805ee9c1cf2ce5a57263287aec5780f04ec324c3514122cfc3231fc1a8b718a62863730a2702bb76366116bed09e0fd" + "d4c860b7074be894fac9697399be5cc1"); ISymmetricEncryptionAlgorithm encryptor = new BouncyCastleXChaCha20(); byte[] cipher = encryptor.Encrypt(message, key, nonce); Assert.IsTrue(expectedCipher.SequenceEqual(cipher)); }
/// <inheritdoc/> public byte[] Unprotect(string protectedData) { // Extract encrypted key and encrypted data string[] parts = protectedData.Split(Separator); if (parts.Length != 3) { throw new Exception("Invalid format of protected data"); } byte[] encryptedStoredKey = CryptoUtils.Base64StringToBytes(parts[0]); byte[] nonce = CryptoUtils.Base64StringToBytes(parts[1]); byte[] protectedDataPart = CryptoUtils.Base64StringToBytes(parts[2]); // Unprotect the random key with OS support byte[] storedKey = null; try { if (KeysExistInKeyStore()) { Cipher cipher = Cipher.GetInstance("RSA/ECB/PKCS1Padding"); // ECB mode is not used by RSA IKey privateKey = GetPrivateKeyFromKeyStore(); cipher.Init(CipherMode.DecryptMode, privateKey); storedKey = cipher.DoFinal(encryptedStoredKey); } } catch (Exception) { storedKey = null; } // Fallback to obfuscated key if (storedKey == null) { storedKey = CryptoUtils.Deobfuscate(encryptedStoredKey, CryptoUtils.StringToSecureString(Obcake)); } // Decrypt the data with the random key ISymmetricEncryptionAlgorithm decryptor; byte[] result; try { decryptor = new BouncyCastleXChaCha20(); result = decryptor.Decrypt(protectedDataPart, storedKey, nonce); } catch (Exception) { // Fallback to twofish, which was used before 3.2021 decryptor = new BouncyCastleTwofishGcm(); result = decryptor.Decrypt(protectedDataPart, storedKey, nonce); } return(result); }
public void EnsureCompatibilityToLibsodiumXChaCha20() { // Ensure that a once stored cipher can always be decrypted even after changes in the liberary. // This cypher was created with libsodium. string base64Cipher = "q8w/Zotsi3ZJp2eaAnFmMiAGgko+N2TkNgunS5+bDRNqrBBoN+XMQPSt7ojO4ODMP3Rf3aoYMNeJFL2/ZqK3AngIuQ=="; byte[] cipher = CryptoUtils.Base64StringToBytes(base64Cipher); ISymmetricEncryptionAlgorithm decryptor = new BouncyCastleXChaCha20(); ICryptoRandomService randomGenerator = CommonMocksAndStubs.CryptoRandomService(88); byte[] key = randomGenerator.GetRandomBytes(decryptor.ExpectedKeySize); byte[] nonce = randomGenerator.GetRandomBytes(decryptor.ExpectedNonceSize); string decryptedMessage = CryptoUtils.BytesToString(decryptor.Decrypt(cipher, key, nonce)); Assert.AreEqual("The brown fox jumps over the lazy 🐢🖐🏿 doc.", decryptedMessage); }
/// <inheritdoc/> public string Protect(byte[] unprotectedData) { // Encrypt the data with a new random key ISymmetricEncryptionAlgorithm encryptor = new BouncyCastleXChaCha20(); byte[] randomKey = _randomService.GetRandomBytes(encryptor.ExpectedKeySize); byte[] nonce = _randomService.GetRandomBytes(encryptor.ExpectedNonceSize); byte[] protectedData = encryptor.Encrypt(unprotectedData, randomKey, nonce); // Protect the random key with the OS support byte[] encryptedRandomKey; try { if (!KeysExistInKeyStore()) { CreateKeyPairInKeyStore(); } Cipher cipher = Cipher.GetInstance("RSA/ECB/PKCS1Padding"); // ECB mode is not used by RSA IKey publicKey = GetPublicKeyFromKeyStore(); cipher.Init(CipherMode.EncryptMode, publicKey); encryptedRandomKey = cipher.DoFinal(randomKey); } catch (Exception) { // Seems there are exotic devices, which do not support the keystore properly. // The least we can do is obfuscating the key. encryptedRandomKey = CryptoUtils.Obfuscate(randomKey, CryptoUtils.StringToSecureString(Obcake), _randomService); } // Combine the encrypted random key and the encrypted data StringBuilder result = new StringBuilder(); result.Append(CryptoUtils.BytesToBase64String(encryptedRandomKey)); result.Append(Separator); result.Append(CryptoUtils.BytesToBase64String(nonce)); result.Append(Separator); result.Append(CryptoUtils.BytesToBase64String(protectedData)); return(result.ToString()); }