3using System.Security.Cryptography;
5using System.Threading.Tasks;
20 protected readonly
static RandomNumberGenerator
rnd = RandomNumberGenerator.Create();
60 default:
throw new ArgumentException(
"Unrecognized algorithm: " + Algorithm.ToString(), nameof(Algorithm));
80 public abstract byte[]
GetIV(
string Id,
string Type,
string From,
string To, uint Counter);
101 public virtual byte[]
Encrypt(
byte[] Data,
byte[] Key,
byte[] IV,
byte[] AssociatedData,
115 int ContentLen = c + d;
117 byte[] Encrypted =
new byte[BlockLen];
124 Encrypted[j] = (byte)(i & 127);
127 Encrypted[j] |= 0x80;
133 Array.Copy(Data, 0, Encrypted, j, c);
135 if (ContentLen < BlockLen)
137 switch (FillAlgorithm)
141 c = BlockLen - ContentLen;
142 byte[] Bin =
new byte[c];
149 Array.Copy(Bin, 0, Encrypted, ContentLen, c);
168 public virtual byte[]
Decrypt(
byte[] Data,
byte[] Key,
byte[] IV,
byte[] AssociatedData)
179 c |= (b & 127) << Offset;
184 if (c < 0 || c + i > Data.Length)
187 byte[] Decrypted =
new byte[c];
189 Array.Copy(Data, i, Decrypted, 0, c);
202 public virtual async Task
Encrypt(Stream Data, Stream Encrypted,
byte[] Key,
byte[] IV,
byte[] AssociatedData)
204 long c = Data.Length;
215 long ContentLen = c + d;
228 Encrypted.WriteByte(b);
232 await Data.CopyToAsync(Encrypted);
234 if (ContentLen < BlockLen)
236 c = BlockLen - ContentLen;
237 byte[] Bin =
new byte[c];
244 await Encrypted.WriteAsync(Bin, 0, (
int)c);
256 public virtual async Task<Stream>
Decrypt(Stream Data,
byte[] Key,
byte[] IV,
byte[] AssociatedData)
268 c |= (i & 127) << Offset;
273 if (c < 0 || c + Data.Position > Data.Length)
313 byte[] IV = this.
GetIV(Id, Type, From, To, Counter);
314 byte[] AssociatedData = this.AuthenticatedEncryption ? Encoding.UTF8.GetBytes(From) :
null;
330 l = EncryptedKey.Length;
335 i = Encrypted.Length;
341 Signature = Sender.
Sign(Data);
342 k = Signature.Length;
358 Block[j++] = (byte)k;
361 Block[j++] = (byte)(k | 128);
362 Block[j++] = (byte)(k >> 7);
368 Block[j++] = (byte)l;
369 Block[j++] = (byte)(l >> 8);
372 Block[j++] = (byte)i;
373 Block[j++] = (byte)(i >> 8);
374 Block[j++] = (byte)(i >> 16);
375 Block[j++] = (byte)(i >> 24);
377 Block[j++] = (byte)Counter;
378 Block[j++] = (byte)(Counter >> 8);
379 Block[j++] = (byte)(Counter >> 16);
380 Block[j++] = (byte)(Counter >> 24);
384 Array.Copy(Signature, 0, Block, j, k);
390 Array.Copy(EncryptedKey, 0, Block, j, l);
394 Array.Copy(Encrypted, 0, Block, j, i);
423 SignatureLen = Data[i++];
424 if ((SignatureLen & 128) != 0)
427 SignatureLen |= Data[i++] << 7;
438 KeyLen |= Data[i++] << 8;
441 if (i + 4 > Data.Length)
445 DataLen |= Data[i++] << 8;
446 DataLen |= Data[i++] << 16;
447 DataLen |= Data[i++] << 24;
450 Counter |= (uint)(Data[i++] << 8);
451 Counter |= (uint)(Data[i++] << 16);
452 Counter |= (uint)(Data[i++] << 24);
454 if (Data.Length != i + SignatureLen + KeyLen + DataLen)
457 byte[] Signature =
new byte[SignatureLen];
458 byte[] EncryptedKey = KeyLen > 0 ?
new byte[KeyLen] :
null;
459 byte[] Encrypted =
new byte[DataLen];
462 Array.Copy(Data, i, Signature, 0, SignatureLen);
467 Array.Copy(Data, i, EncryptedKey, 0, KeyLen);
471 Array.Copy(Data, i, Encrypted, 0, DataLen);
473 if (EncryptedKey is
null)
479 byte[] IV = this.
GetIV(Id, Type, From, To, Counter);
480 byte[] AssociatedData = this.AuthenticatedEncryption ? Encoding.UTF8.GetBytes(From) :
null;
484 Decrypted = this.
Decrypt(Encrypted, Key, IV, AssociatedData);
486 if (!(Decrypted is
null) &&
502 if (EncryptedKey is
null)
509 Decrypted = this.
Decrypt(Encrypted, Key, IV, AssociatedData);
511 if (!(Decrypted is
null) &&
541 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;
563 l = EncryptedKey.Length;
566 await this.
Encrypt(Data, TempEncrypted, Key, IV, AssociatedData);
569 if (i > uint.MaxValue)
570 throw new NotSupportedException(
"Too large.");
575 Signature = Sender.
Sign(Data);
576 k = Signature.Length;
587 Encrypted.WriteByte((
byte)k);
590 Encrypted.WriteByte((
byte)(k | 128));
591 Encrypted.WriteByte((
byte)(k >> 7));
597 Encrypted.WriteByte((
byte)l);
598 Encrypted.WriteByte((
byte)(l >> 8));
601 Encrypted.WriteByte((
byte)i);
602 Encrypted.WriteByte((
byte)(i >> 8));
603 Encrypted.WriteByte((
byte)(i >> 16));
604 Encrypted.WriteByte((
byte)(i >> 24));
606 Encrypted.WriteByte((
byte)Counter);
607 Encrypted.WriteByte((
byte)(Counter >> 8));
608 Encrypted.WriteByte((
byte)(Counter >> 16));
609 Encrypted.WriteByte((
byte)(Counter >> 24));
612 await Encrypted.WriteAsync(Signature, 0, k);
615 await Encrypted.WriteAsync(EncryptedKey, 0, l);
617 TempEncrypted.Position = 0;
645 SignatureLen = Data.ReadByte();
646 if ((SignatureLen & 128) != 0)
649 SignatureLen |= Data.ReadByte() << 7;
659 KeyLen = Data.ReadByte();
660 KeyLen |= Data.ReadByte() << 8;
663 if (Data.Position + 4 > Data.Length)
666 DataLen = Data.ReadByte();
667 DataLen |= Data.ReadByte() << 8;
668 DataLen |= Data.ReadByte() << 16;
669 DataLen |= Data.ReadByte() << 24;
671 Counter = (byte)Data.ReadByte();
672 Counter |= (uint)(Data.ReadByte() << 8);
673 Counter |= (uint)(Data.ReadByte() << 16);
674 Counter |= (uint)(Data.ReadByte() << 24);
676 if (Data.Length != Data.Position + SignatureLen + KeyLen + DataLen)
679 byte[] Signature =
new byte[SignatureLen];
680 byte[] EncryptedKey = KeyLen > 0 ?
new byte[KeyLen] :
null;
683 if (await Data.ReadAsync(Signature, 0, SignatureLen) != SignatureLen)
688 if (await Data.ReadAsync(EncryptedKey, 0, KeyLen) != KeyLen)
696 if (EncryptedKey is
null)
701 byte[] IV = this.
GetIV(Id, Type, From, To, Counter);
702 byte[] AssociatedData = this.AuthenticatedEncryption ? Encoding.UTF8.GetBytes(From) :
null;
703 Stream Decrypted =
null;
707 Encrypted.Position = 0;
708 Decrypted = await this.
Decrypt(Encrypted, Key, IV, AssociatedData);
710 if (!(Decrypted is
null))
712 Decrypted.Position = 0;
728 Decrypted?.Dispose();
736 if (EncryptedKey is
null)
743 Encrypted.Position = 0;
744 Decrypted = await this.
Decrypt(Encrypted, Key, IV, AssociatedData);
746 if (!(Decrypted is
null))
748 Decrypted.Position = 0;
765 Decrypted?.Dispose();
789 public virtual bool Encrypt(
string Id,
string Type,
string From,
string To, uint Counter,
byte[] Data,
794 byte[] IV = this.
GetIV(Id, Type, From, To, Counter);
795 byte[] AssociatedData = this.AuthenticatedEncryption ? Encoding.UTF8.GetBytes(From) :
null;
799 Xml.Append(
" xmlns=\"");
800 Xml.Append(this.Namespace);
801 Xml.Append(
"\" r=\"");
808 Xml.Append(
"\" c=\"");
809 Xml.Append(Counter.ToString());
819 Xml.Append(
"\" k=\"");
820 Xml.Append(Convert.ToBase64String(EncryptedKey));
827 byte[] Signature = Sender.
Sign(Data);
829 Xml.Append(
"\" s=\"");
830 Xml.Append(Convert.ToBase64String(Signature));
834 Xml.Append(Convert.ToBase64String(Encrypted));
853 public virtual string Decrypt(
string Id,
string Type,
string From,
string To, XmlElement Xml,
856 byte[] EncryptedKey =
null;
857 byte[] Signature =
null;
858 uint? Counter =
null;
860 foreach (XmlAttribute Attr
in Xml.Attributes)
865 if (!uint.TryParse(Attr.Value, out uint i))
872 Signature = Convert.FromBase64String(Attr.Value);
876 EncryptedKey = Convert.FromBase64String(Attr.Value);
881 if (!Counter.HasValue)
884 byte[] Encrypted = Convert.FromBase64String(Xml.InnerText);
888 if (EncryptedKey is
null)
889 Key = Receiver.GetSharedSecret(Sender);
891 Key = Receiver.DecryptSecret(EncryptedKey);
893 byte[] IV = this.
GetIV(Id, Type, From, To, Counter.Value);
894 byte[] AssociatedData = this.AuthenticatedEncryption ? Encoding.UTF8.GetBytes(From) :
null;
898 Decrypted = this.
Decrypt(Encrypted, Key, IV, AssociatedData);
900 if (!(Decrypted is
null) &&
901 ((Sender.SupportsSignatures && Sender.Verify(Decrypted, Signature)) ||
902 (!Sender.SupportsSignatures && Signature is
null)))
904 return Encoding.UTF8.GetString(Decrypted);
912 if (!(Receiver.Previous is
null))
916 if (EncryptedKey is
null)
917 Key = Receiver.Previous.GetSharedSecret(Sender);
919 Key = Receiver.Previous.DecryptSecret(EncryptedKey);
923 Decrypted = this.
Decrypt(Encrypted, Key, IV, AssociatedData);
925 if (!(Decrypted is
null) &&
926 ((Sender.SupportsSignatures && Sender.Verify(Decrypted, Signature)) ||
927 (!Sender.SupportsSignatures && Signature is
null)))
929 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.
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 async Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken)
Asynchronously reads the bytes from the current stream and writes them to another stream,...
override void Dispose(bool disposing)
Releases the unmanaged resources used by the System.IO.Stream and optionally releases the managed res...
override long Length
When overridden in a derived class, gets the length in bytes of the stream.
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.
byte[] GetSharedSecret(IE2eEndpoint RemoteEndpoint)
Gets a shared secret
bool SupportsSharedSecrets
If shared secrets can be calculated from the endpoints keys.
bool Verify(byte[] Data, byte[] Signature)
Verifies a signature.
string Namespace
Namespace of the E2E endpoint
byte[] EncryptSecret(byte[] Secret)
Encrypts a secret. Used if shared secrets cannot be calculated.
string LocalName
Local name of the E2E endpoint
byte[] DecryptSecret(byte[] Secret)
Decrypts a secret. Used if shared secrets cannot be calculated.
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.