5using System.Threading.Tasks;
21 protected readonly
static RandomNumberGenerator
rnd = RandomNumberGenerator.Create();
53 return Algorithm
switch
55 SymmetricCipherAlgorithms.Aes256 =>
new Aes256(),
56 SymmetricCipherAlgorithms.ChaCha20 =>
new ChaCha20(),
58 _ =>
throw new ArgumentException(
"Unrecognized algorithm: " + Algorithm.ToString(), nameof(Algorithm)),
85 public abstract byte[]
GetIV(
string Id,
string Type,
string From,
string To, uint Counter);
106 public virtual byte[]
Encrypt(
byte[] Data,
byte[] Key,
byte[] IV,
byte[] AssociatedData,
120 int ContentLen = c + d;
122 byte[] Encrypted =
new byte[BlockLen];
129 Encrypted[j] = (byte)(i & 127);
132 Encrypted[j] |= 0x80;
138 Buffer.BlockCopy(Data, 0, Encrypted, j, c);
140 if (ContentLen < BlockLen)
142 switch (FillAlgorithm)
146 c = BlockLen - ContentLen;
147 byte[] Bin =
new byte[c];
154 Buffer.BlockCopy(Bin, 0, Encrypted, ContentLen, c);
173 public virtual byte[]
Decrypt(
byte[] Data,
byte[] Key,
byte[] IV,
byte[] AssociatedData)
184 c |= (b & 127) << Offset;
189 if (c < 0 || c + i > Data.Length)
192 byte[] Decrypted =
new byte[c];
194 Buffer.BlockCopy(Data, i, Decrypted, 0, c);
207 public virtual async Task
Encrypt(Stream Data, Stream Encrypted,
byte[] Key,
byte[] IV,
byte[] AssociatedData)
209 long c = Data.Length;
220 long ContentLen = c + d;
233 Encrypted.WriteByte(b);
237 await Data.CopyToAsync(Encrypted);
239 if (ContentLen < BlockLen)
241 c = BlockLen - ContentLen;
242 byte[] Bin =
new byte[c];
249 await Encrypted.WriteAsync(Bin, 0, (
int)c);
261 public virtual async Task<Stream>
Decrypt(Stream Data,
byte[] Key,
byte[] IV,
byte[] AssociatedData)
273 c |= (i & 127) << Offset;
278 if (c < 0 || c + Data.Position > Data.Length)
317 byte[] IV = this.
GetIV(Id, Type, From, To, Counter);
318 byte[] AssociatedData = this.AuthenticatedEncryption ? Encoding.UTF8.GetBytes(From) :
null;
325 if (KeyCipherText is
null)
335 throw new InvalidOperationException(
"Shared secret ciphertexts not supported.");
337 l = KeyCipherText.Length;
342 i = Encrypted.Length;
348 Signature = Sender.
Sign(Data);
349 k = Signature.Length;
365 Block[j++] = (byte)k;
368 Block[j++] = (byte)(k | 128);
369 Block[j++] = (byte)(k >> 7);
375 Block[j++] = (byte)l;
376 Block[j++] = (byte)(l >> 8);
379 Block[j++] = (byte)i;
380 Block[j++] = (byte)(i >> 8);
381 Block[j++] = (byte)(i >> 16);
382 Block[j++] = (byte)(i >> 24);
384 Block[j++] = (byte)Counter;
385 Block[j++] = (byte)(Counter >> 8);
386 Block[j++] = (byte)(Counter >> 16);
387 Block[j++] = (byte)(Counter >> 24);
391 Buffer.BlockCopy(Signature, 0, Block, j, k);
397 Buffer.BlockCopy(KeyCipherText, 0, Block, j, l);
401 Buffer.BlockCopy(Encrypted, 0, Block, j, i);
430 SignatureLen = Data[i++];
431 if ((SignatureLen & 128) != 0)
434 SignatureLen |= Data[i++] << 7;
443 KeyLen |= Data[i++] << 8;
448 if (i + 4 > Data.Length)
452 DataLen |= Data[i++] << 8;
453 DataLen |= Data[i++] << 16;
454 DataLen |= Data[i++] << 24;
457 Counter |= (uint)(Data[i++] << 8);
458 Counter |= (uint)(Data[i++] << 16);
459 Counter |= (uint)(Data[i++] << 24);
461 if (Data.Length != i + SignatureLen + KeyLen + DataLen)
464 byte[] Signature =
new byte[SignatureLen];
465 byte[] KeyCipherText = KeyLen > 0 ?
new byte[KeyLen] :
null;
466 byte[] Encrypted =
new byte[DataLen];
469 Buffer.BlockCopy(Data, i, Signature, 0, SignatureLen);
474 Buffer.BlockCopy(Data, i, KeyCipherText, 0, KeyLen);
478 Buffer.BlockCopy(Data, i, Encrypted, 0, DataLen);
483 byte[] IV = this.
GetIV(Id, Type, From, To, Counter);
484 byte[] AssociatedData = this.AuthenticatedEncryption ? Encoding.UTF8.GetBytes(From) :
null;
488 Decrypted = this.
Decrypt(Encrypted, Key, IV, AssociatedData);
490 if (!(Decrypted is
null) &&
510 Decrypted = this.
Decrypt(Encrypted, Key, IV, AssociatedData);
512 if (!(Decrypted is
null) &&
542 public virtual async Task
Encrypt(
string Id,
string Type,
string From,
string To, uint Counter, Stream Data, Stream Encrypted,
IE2eEndpoint Sender,
IE2eEndpoint Receiver)
547 byte[] IV = this.
GetIV(Id, Type, From, To, Counter);
548 byte[] AssociatedData = this.AuthenticatedEncryption ? Encoding.UTF8.GetBytes(From) :
null;
554 if (KeyCipherText is
null)
559 throw new InvalidOperationException(
"Shared secret ciphertexts not supported.");
561 l = KeyCipherText.Length;
564 await this.
Encrypt(Data, TempEncrypted, Key, IV, AssociatedData);
565 i = TempEncrypted.Length;
567 if (i > uint.MaxValue)
568 throw new NotSupportedException(
"Too large.");
573 Signature = Sender.
Sign(Data);
574 k = Signature.Length;
585 Encrypted.WriteByte((
byte)k);
588 Encrypted.WriteByte((
byte)(k | 128));
589 Encrypted.WriteByte((
byte)(k >> 7));
595 Encrypted.WriteByte((
byte)l);
596 Encrypted.WriteByte((
byte)(l >> 8));
599 Encrypted.WriteByte((
byte)i);
600 Encrypted.WriteByte((
byte)(i >> 8));
601 Encrypted.WriteByte((
byte)(i >> 16));
602 Encrypted.WriteByte((
byte)(i >> 24));
604 Encrypted.WriteByte((
byte)Counter);
605 Encrypted.WriteByte((
byte)(Counter >> 8));
606 Encrypted.WriteByte((
byte)(Counter >> 16));
607 Encrypted.WriteByte((
byte)(Counter >> 24));
610 await Encrypted.WriteAsync(Signature, 0, k);
613 await Encrypted.WriteAsync(KeyCipherText, 0, l);
615 TempEncrypted.Position = 0;
616 await TempEncrypted.CopyToAsync(Encrypted);
642 SignatureLen = Data.ReadByte();
643 if ((SignatureLen & 128) != 0)
646 SignatureLen |= Data.ReadByte() << 7;
654 KeyLen = Data.ReadByte();
655 KeyLen |= Data.ReadByte() << 8;
660 if (Data.Position + 4 > Data.Length)
663 DataLen = Data.ReadByte();
664 DataLen |= Data.ReadByte() << 8;
665 DataLen |= Data.ReadByte() << 16;
666 DataLen |= Data.ReadByte() << 24;
668 Counter = (byte)Data.ReadByte();
669 Counter |= (uint)(Data.ReadByte() << 8);
670 Counter |= (uint)(Data.ReadByte() << 16);
671 Counter |= (uint)(Data.ReadByte() << 24);
673 if (Data.Length != Data.Position + SignatureLen + KeyLen + DataLen)
676 byte[] Signature =
new byte[SignatureLen];
677 byte[] KeyCipherText = KeyLen > 0 ?
new byte[KeyLen] :
null;
680 if (await Data.TryReadAllAsync(Signature, 0, SignatureLen) != SignatureLen)
685 if (await Data.TryReadAllAsync(KeyCipherText, 0, KeyLen) != KeyLen)
695 byte[] IV = this.
GetIV(Id, Type, From, To, Counter);
696 byte[] AssociatedData = this.AuthenticatedEncryption ? Encoding.UTF8.GetBytes(From) :
null;
697 Stream Decrypted =
null;
701 Encrypted.Position = 0;
702 Decrypted = await this.
Decrypt(Encrypted, Key, IV, AssociatedData);
704 if (!(Decrypted is
null))
706 Decrypted.Position = 0;
722 Decrypted?.Dispose();
734 Encrypted.Position = 0;
735 Decrypted = await this.
Decrypt(Encrypted, Key, IV, AssociatedData);
737 if (!(Decrypted is
null))
739 Decrypted.Position = 0;
756 Decrypted?.Dispose();
779 public virtual bool Encrypt(
string Id,
string Type,
string From,
string To, uint Counter,
byte[] Data,
784 byte[] IV = this.
GetIV(Id, Type, From, To, Counter);
785 byte[] AssociatedData = this.AuthenticatedEncryption ? Encoding.UTF8.GetBytes(From) :
null;
789 Xml.Append(
" xmlns=\"");
790 Xml.Append(this.Namespace);
791 Xml.Append(
"\" r=\"");
798 Xml.Append(
"\" c=\"");
799 Xml.Append(Counter.ToString());
803 if (!(KeyCipherText is
null))
806 throw new InvalidOperationException(
"Shared secret ciphertexts not supported.");
808 Xml.Append(
"\" k=\"");
809 Xml.Append(Convert.ToBase64String(KeyCipherText));
816 byte[] Signature = Sender.
Sign(Data);
818 Xml.Append(
"\" s=\"");
819 Xml.Append(Convert.ToBase64String(Signature));
823 Xml.Append(Convert.ToBase64String(Encrypted));
842 public virtual string Decrypt(
string Id,
string Type,
string From,
string To, XmlElement Xml,
845 byte[] KeyCipherText =
null;
846 byte[] Signature =
null;
847 uint? Counter =
null;
849 foreach (XmlAttribute Attr
in Xml.Attributes)
854 if (!uint.TryParse(Attr.Value, out uint i))
861 Signature = Convert.FromBase64String(Attr.Value);
865 KeyCipherText = Convert.FromBase64String(Attr.Value);
870 if (!Counter.HasValue)
873 byte[] Encrypted = Convert.FromBase64String(Xml.InnerText);
877 Key = Receiver.GetSharedSecretForDecryption(Sender, KeyCipherText);
879 byte[] IV = this.
GetIV(Id, Type, From, To, Counter.Value);
880 byte[] AssociatedData = this.AuthenticatedEncryption ? Encoding.UTF8.GetBytes(From) :
null;
884 Decrypted = this.
Decrypt(Encrypted, Key, IV, AssociatedData);
886 if (!(Decrypted is
null) &&
887 ((Sender.SupportsSignatures && Sender.Verify(Decrypted, Signature)) ||
888 (!Sender.SupportsSignatures && Signature is
null)))
890 return Encoding.UTF8.GetString(Decrypted);
898 if (!(Receiver.Previous is
null))
902 Key = Receiver.Previous.GetSharedSecretForDecryption(Sender, KeyCipherText);
906 Decrypted = this.
Decrypt(Encrypted, Key, IV, AssociatedData);
908 if (!(Decrypted is
null) &&
909 ((Sender.SupportsSignatures && Sender.Verify(Decrypted, Signature)) ||
910 (!Sender.SupportsSignatures && Signature is
null)))
912 return Encoding.UTF8.GetString(Decrypted);
Class managing end-to-end encryption.
const string IoTHarmonizationE2ECurrent
Current namespace for End-to-End encryption.
Implements support for the AEAD-ChaCha20-Poly1305 cipher in hybrid End-to-End encryption schemes.
Implements support for the AES-256 cipher in hybrid End-to-End encryption schemes.
Implements support for the ChaCha20 cipher in hybrid End-to-End encryption schemes.
Abstract base class for symmetric ciphers.
abstract byte[] GetIV(string Id, string Type, string From, string To, uint Counter)
Gets an Initiation Vector from stanza attributes.
abstract bool Supported(XmlElement E2e)
If the symmetric cipher is supported by a remote endpoint.
static IE2eSymmetricCipher Create(SymmetricCipherAlgorithms Algorithm)
Creates an instance of a symmetric cipher algorithm.
virtual bool Encrypt(string Id, string Type, string From, string To, uint Counter, byte[] Data, StringBuilder Xml, IE2eEndpoint Sender, IE2eEndpoint Receiver)
Encrypts Binary data
virtual async Task Encrypt(string Id, string Type, string From, string To, uint Counter, Stream Data, Stream Encrypted, IE2eEndpoint Sender, IE2eEndpoint Receiver)
Encrypts binary data
virtual void Dispose()
IDisposable.Dispose
virtual string Decrypt(string Id, string Type, string From, string To, XmlElement Xml, IE2eEndpoint Sender, IE2eEndpoint Receiver)
Decrypts XML data
abstract byte[] GenerateKey()
Generates a new key. Used when the asymmetric cipher cannot calculate a shared secret.
virtual byte[] Encrypt(string Id, string Type, string From, string To, uint Counter, byte[] Data, IE2eEndpoint Sender, IE2eEndpoint Receiver)
Encrypts binary data
virtual long GetEncryptedLength(long ContentLength)
Calculates the minimum size of encrypted data, given the size of the content.
virtual bool AuthenticatedEncryption
If Authenticated Encryption with Associated Data is used
abstract IE2eSymmetricCipher CreteNew()
Creates a new symmetric cipher object with the same settings as the current object.
static readonly RandomNumberGenerator rnd
Random number generator.
virtual byte[] Decrypt(byte[] Data, byte[] Key, byte[] IV, byte[] AssociatedData)
Decrypts binary data
abstract string LocalName
Local name of the E2E symmetric cipher
virtual async Task Encrypt(Stream Data, Stream Encrypted, byte[] Key, byte[] IV, byte[] AssociatedData)
Encrypts binary data
virtual byte[] Decrypt(string Id, string Type, string From, string To, byte[] Data, IE2eEndpoint Sender, IE2eEndpoint Receiver)
Decrypts binary data
virtual async Task< Stream > Decrypt(Stream Data, byte[] Key, byte[] IV, byte[] AssociatedData)
Decrypts binary data
virtual string Namespace
Namespace of the E2E symmetric cipher
virtual byte[] Encrypt(byte[] Data, byte[] Key, byte[] IV, byte[] AssociatedData, E2eBufferFillAlgorithm FillAlgorithm)
Encrypts binary data
virtual async Task< Stream > Decrypt(string Id, string Type, string From, string To, Stream Data, IE2eEndpoint Sender, IE2eEndpoint Receiver)
Decrypts binary data
Manages a temporary stream. Contents is kept in-memory, if below a memory threshold,...
override void Dispose(bool disposing)
Releases the unmanaged resources used by the System.IO.Stream and optionally releases the managed res...
Helper methods for encrypting and decrypting streams of data.
static async Task< bool > CopyAsync(Stream From, Stream To, long DataLen)
Copies DataLen number of bytes from From to To .
Abstract base class for End-to-End encryption schemes.
bool SupportsSignatures
If signatures are supported.
byte[] Sign(byte[] Data)
Signs binary data using the local private key.
bool Verify(byte[] Data, byte[] Signature)
Verifies a signature.
string Namespace
Namespace of the E2E endpoint
bool SharedSecretUseCipherText
If the recipient needs a cipher text to generate the same shared secret.
byte[] GetSharedSecretForDecryption(IE2eEndpoint RemoteEndpoint, byte[] CipherText)
Gets a shared secret for decryption.
byte[] GetSharedSecretForEncryption(IE2eEndpoint RemoteEndpoint, IE2eSymmetricCipher Cipher, out byte[] CipherText)
Gets a shared secret for encryption, and optionally a corresponding cipher text.
string LocalName
Local name of the E2E endpoint
IE2eEndpoint Previous
Previous keys.
Interface for symmetric ciphers.
SymmetricCipherAlgorithms
Enumeration of symmetric cipher algorithms available in the library.
E2eBufferFillAlgorithm
How buffers are filler before E2E Encryption is performed.