private async Task Test_Stream(IE2eEndpoint Endpoint1, IE2eEndpoint Endpoint2) { MemoryStream Data = new MemoryStream(); byte[] Temp = new byte[1024]; byte[] Temp2 = new byte[1024]; int i; using (RandomNumberGenerator Rnd = RandomNumberGenerator.Create()) { for (i = 0; i < 1024; i++) { Rnd.GetBytes(Temp); Data.Write(Temp, 0, Temp.Length); } } MemoryStream Encrypted = new MemoryStream(); Data.Position = 0; await Endpoint1.DefaultSymmetricCipher.Encrypt( "ID", "Type", "From", "To", 1, Data, Encrypted, Endpoint1, Endpoint2); Encrypted.Position = 0; Stream Decrypted = await Endpoint2.DefaultSymmetricCipher.Decrypt( "ID", "Type", "From", "To", Encrypted, Endpoint1, Endpoint2); Assert.IsNotNull(Decrypted, "Decryption failed."); long c = Data.Length; Assert.AreEqual(c, Decrypted.Length, "Length mismatch."); Decrypted.Position = 0; Data.Position = 0; while (true) { i = await Data.ReadAsync(Temp, 0, Temp.Length); Assert.AreEqual(i, await Decrypted.ReadAsync(Temp2, 0, Temp2.Length)); if (i <= 0) { break; } while (i > 0) { i--; Assert.AreEqual(Temp[i], Temp2[i], "Encryption/Decryption failed."); } } }
/// <summary> /// Encrypts Binary data /// </summary> /// <param name="Id">Id attribute</param> /// <param name="Type">Type attribute</param> /// <param name="From">From attribute</param> /// <param name="To">To attribute</param> /// <param name="Counter">Counter. Can be reset every time a new key is generated. /// A new key must be generated before the counter wraps.</param> /// <param name="Data">Binary data to encrypt</param> /// <param name="Xml">XML output</param> /// <param name="Sender">Local endpoint performing the encryption.</param> /// <param name="Receiver">Remote endpoint performing the decryption.</param> /// <returns>If encryption was possible</returns> public virtual bool Encrypt(string Id, string Type, string From, string To, uint Counter, byte[] Data, StringBuilder Xml, IE2eEndpoint Sender, IE2eEndpoint Receiver) { byte[] Encrypted; byte[] Key; byte[] IV = this.GetIV(Id, Type, From, To, Counter); byte[] AssociatedData = this.AuthenticatedEncryption ? Encoding.UTF8.GetBytes(From) : null; Xml.Append('<'); Xml.Append(this.LocalName); Xml.Append(" xmlns=\""); Xml.Append(this.Namespace); Xml.Append("\" r=\""); if (Sender.Namespace != EndpointSecurity.IoTHarmonizationE2E) { Xml.Append(Sender.Namespace); Xml.Append('#'); } Xml.Append(Sender.LocalName); Xml.Append("\" c=\""); Xml.Append(Counter.ToString()); if (Sender.SupportsSharedSecrets) { Key = Sender.GetSharedSecret(Receiver); } else { Key = this.GenerateKey(); byte[] EncryptedKey = Receiver.EncryptSecret(Key); Xml.Append("\" k=\""); Xml.Append(Convert.ToBase64String(EncryptedKey)); } Encrypted = this.Encrypt(Data, Key, IV, AssociatedData); if (Sender.SupportsSignatures) { byte[] Signature = Sender.Sign(Data); Xml.Append("\" s=\""); Xml.Append(Convert.ToBase64String(Signature)); } Xml.Append("\">"); Xml.Append(Convert.ToBase64String(Encrypted)); Xml.Append("</"); Xml.Append(this.LocalName); Xml.Append('>'); return(true); }
private void Test_Binary(IE2eEndpoint Endpoint1, IE2eEndpoint Endpoint2) { byte[] Data = new byte[1024]; using (RandomNumberGenerator Rnd = RandomNumberGenerator.Create()) { Rnd.GetBytes(Data); } byte[] Encrypted = Endpoint1.DefaultSymmetricCipher.Encrypt( "ID", "Type", "From", "To", 1, Data, Endpoint1, Endpoint2); byte[] Decrypted = Endpoint2.DefaultSymmetricCipher.Decrypt( "ID", "Type", "From", "To", Encrypted, Endpoint1, Endpoint2); Assert.IsNotNull(Decrypted, "Decryption failed."); int i, c = Data.Length; Assert.AreEqual(c, Decrypted.Length, "Length mismatch."); for (i = 0; i < c; i++) { Assert.AreEqual(Data[i], Decrypted[i], "Encryption/Decryption failed."); } }
/// <summary> /// Parses an identity from its XML representation /// </summary> /// <param name="Xml">XML representation</param> /// <returns>Legal identity</returns> public static LegalIdentity Parse(XmlElement Xml) { List <Property> Properties = new List <Property>(); LegalIdentity Result = new LegalIdentity() { id = XML.Attribute(Xml, "id") }; foreach (XmlNode N in Xml.ChildNodes) { if (N is XmlElement E) { switch (E.LocalName) { case "clientPublicKey": foreach (XmlNode N2 in E.ChildNodes) { if (N2 is XmlElement E2) { IE2eEndpoint Key = EndpointSecurity.ParseE2eKey(E2); if (Key != null && Key.Namespace == EndpointSecurity.IoTHarmonizationE2E) { if (Key is RsaAes RsaAes) { Result.clientKeyName = "RSA" + RsaAes.KeySize.ToString(); Result.clientPubKey1 = RsaAes.Modulus; Result.clientPubKey2 = RsaAes.Exponent; } else if (Key is EcAes256 EcAes256) { Result.clientKeyName = Key.LocalName; Result.ClientPubKey1 = EcAes256.ToNetwork(EcAes256.PublicKey.X); Result.ClientPubKey2 = EcAes256.ToNetwork(EcAes256.PublicKey.Y); } } } } break; case "property": string Name = XML.Attribute(E, "name"); string Value = XML.Attribute(E, "value"); Properties.Add(new Property(Name, Value)); break; case "clientSignature": foreach (XmlAttribute Attr in E.Attributes) { switch (Attr.Name) { case "s1": Result.clientSignature1 = Convert.FromBase64String(Attr.Value); break; case "s2": Result.clientSignature2 = Convert.FromBase64String(Attr.Value); break; } } break; case "status": foreach (XmlAttribute Attr in E.Attributes) { switch (Attr.Name) { case "provider": Result.provider = Attr.Value; break; case "state": if (Enum.TryParse <IdentityState>(Attr.Value, out IdentityState IdentityState)) { Result.state = IdentityState; } break; case "created": if (XML.TryParse(Attr.Value, out DateTime TP)) { Result.created = TP; } break; case "updated": if (XML.TryParse(Attr.Value, out TP)) { Result.updated = TP; } break; case "from": if (XML.TryParse(Attr.Value, out TP)) { Result.from = TP; } break; case "to": if (XML.TryParse(Attr.Value, out TP)) { Result.to = TP; } break; } } break; case "serverSignature": foreach (XmlAttribute Attr in E.Attributes) { switch (Attr.Name) { case "s1": Result.serverSignature1 = Convert.FromBase64String(Attr.Value); break; case "s2": Result.serverSignature2 = Convert.FromBase64String(Attr.Value); break; } } break; } } } Result.properties = Properties.ToArray(); return(Result); }
/// <summary> /// Event arguments for key responses /// </summary> /// <param name="e">IQ response event arguments.</param> /// <param name="Key">Key.</param> public KeyEventArgs(IqResultEventArgs e, IE2eEndpoint Key) : base(e) { this.key = Key; }
/// <summary> /// Decrypts XML data /// </summary> /// <param name="Id">Id attribute</param> /// <param name="Type">Type attribute</param> /// <param name="From">From attribute</param> /// <param name="To">To attribute</param> /// <param name="AesElement">XML element with encrypted data.</param> /// <param name="RemoteEndpoint">Remote endpoint of same type.</param> /// <returns>Decrypted XMLs</returns> public override string Decrypt(string Id, string Type, string From, string To, XmlElement AesElement, IE2eEndpoint RemoteEndpoint) { if (!(RemoteEndpoint is RsaAes RemoteRsaAes)) { return(null); } byte[] KeyEncrypted = Convert.FromBase64String(XML.Attribute(AesElement, "keyRsa")); byte[] Signature = Convert.FromBase64String(XML.Attribute(AesElement, "signRsa")); byte[] Encrypted = Convert.FromBase64String(AesElement.InnerText); byte[] Decrypted; byte[] Key; byte[] IV = this.GetIV(Id, Type, From, To); try { Key = this.Decrypt(KeyEncrypted); Decrypted = this.Decrypt(Encrypted, Key, IV); if (Decrypted != null) { lock (RemoteRsaAes.rsa) { if (!RemoteRsaAes.rsa.VerifyData(Decrypted, Signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pss)) { Decrypted = null; } } } } catch (Exception) { Decrypted = null; } if (Decrypted == null) { try { Key = (this.Previous as RsaAes)?.Decrypt(KeyEncrypted); if (Key != null) { Decrypted = this.Decrypt(Encrypted, Key, IV); if (Decrypted == null) { return(null); } lock (RemoteRsaAes.rsa) { if (!RemoteRsaAes.rsa.VerifyData(Decrypted, Signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pss)) { return(null); } } } else { return(null); } } catch (Exception) { return(null); // Invalid keys. } } return(Encoding.UTF8.GetString(Decrypted)); }
/// <summary> /// Encrypts binary data /// </summary> /// <param name="Id">Id attribute</param> /// <param name="Type">Type attribute</param> /// <param name="From">From attribute</param> /// <param name="To">To attribute</param> /// <param name="Counter">Counter. Can be reset every time a new key is generated. /// A new key must be generated before the counter wraps.</param> /// <param name="Data">Binary data to encrypt</param> /// <param name="Encrypted">Encrypted data will be stored here.</param> /// <param name="Sender">Local endpoint performing the encryption.</param> /// <param name="Receiver">Remote endpoint performing the decryption.</param> public virtual async Task Encrypt(string Id, string Type, string From, string To, uint Counter, Stream Data, Stream Encrypted, IE2eEndpoint Sender, IE2eEndpoint Receiver) { using (TemporaryStream TempEncrypted = new TemporaryStream()) { byte[] EncryptedKey; byte[] Key; byte[] IV = this.GetIV(Id, Type, From, To, Counter); byte[] AssociatedData = this.AuthenticatedEncryption ? Encoding.UTF8.GetBytes(From) : null; byte[] Signature; long i; int k, l; if (Sender.SupportsSharedSecrets) { Key = Sender.GetSharedSecret(Receiver); EncryptedKey = null; l = 0; } else { Key = this.GenerateKey(); EncryptedKey = Receiver.EncryptSecret(Key); l = EncryptedKey.Length; } await this.Encrypt(Data, TempEncrypted, Key, IV, AssociatedData); i = TempEncrypted.Length; if (i > uint.MaxValue) { throw new NotSupportedException("Too large."); } if (Sender.SupportsSignatures) { Data.Position = 0; Signature = Sender.Sign(Data); k = Signature.Length; } else { k = 0; Signature = null; } if (k > 0) { if (k < 128) { Encrypted.WriteByte((byte)k); } else { Encrypted.WriteByte((byte)(k | 128)); Encrypted.WriteByte((byte)(k >> 7)); } } if (l > 0) { Encrypted.WriteByte((byte)l); Encrypted.WriteByte((byte)(l >> 8)); } Encrypted.WriteByte((byte)i); Encrypted.WriteByte((byte)(i >> 8)); Encrypted.WriteByte((byte)(i >> 16)); Encrypted.WriteByte((byte)(i >> 24)); Encrypted.WriteByte((byte)Counter); Encrypted.WriteByte((byte)(Counter >> 8)); Encrypted.WriteByte((byte)(Counter >> 16)); Encrypted.WriteByte((byte)(Counter >> 24)); if (k > 0) { await Encrypted.WriteAsync(Signature, 0, k); } if (l > 0) { await Encrypted.WriteAsync(EncryptedKey, 0, l); } TempEncrypted.Position = 0; await TempEncrypted.CopyToAsync(Encrypted); } }
/// <summary> /// Decrypts XML data /// </summary> /// <param name="Id">Id attribute</param> /// <param name="Type">Type attribute</param> /// <param name="From">From attribute</param> /// <param name="To">To attribute</param> /// <param name="Xml">XML element with encrypted data.</param> /// <param name="Sender">Remote endpoint performing the encryption.</param> /// <param name="Receiver">Local endpoint performing the decryption.</param> /// <returns>Decrypted XMLs</returns> public virtual string Decrypt(string Id, string Type, string From, string To, XmlElement Xml, IE2eEndpoint Sender, IE2eEndpoint Receiver) { byte[] EncryptedKey = null; byte[] Signature = null; uint? Counter = null; foreach (XmlAttribute Attr in Xml.Attributes) { switch (Attr.Name) { case "c": if (!uint.TryParse(Attr.Value, out uint i)) { return(null); } Counter = i; break; case "s": Signature = Convert.FromBase64String(Attr.Value); break; case "k": EncryptedKey = Convert.FromBase64String(Attr.Value); break; } } if (!Counter.HasValue) { return(null); } byte[] Encrypted = Convert.FromBase64String(Xml.InnerText); byte[] Decrypted; byte[] Key; if (EncryptedKey is null) { Key = Receiver.GetSharedSecret(Sender); } else { Key = Receiver.DecryptSecret(EncryptedKey); } byte[] IV = this.GetIV(Id, Type, From, To, Counter.Value); byte[] AssociatedData = this.AuthenticatedEncryption ? Encoding.UTF8.GetBytes(From) : null; try { Decrypted = this.Decrypt(Encrypted, Key, IV, AssociatedData); if (Decrypted != null && ((Sender.SupportsSignatures && Sender.Verify(Decrypted, Signature)) || (!Sender.SupportsSignatures && Signature is null))) { return(Encoding.UTF8.GetString(Decrypted)); } } catch (Exception) { // Invalid key } if (!(Receiver.Previous is null)) { try { if (EncryptedKey is null) { Key = Receiver.Previous.GetSharedSecret(Sender); } else { Key = Receiver.Previous.DecryptSecret(EncryptedKey); } if (Key != null) { Decrypted = this.Decrypt(Encrypted, Key, IV, AssociatedData); if (Decrypted != null && ((Sender.SupportsSignatures && Sender.Verify(Decrypted, Signature)) || (!Sender.SupportsSignatures && Signature is null))) { return(Encoding.UTF8.GetString(Decrypted)); } } } catch (Exception) { // Invalid key } } return(null); }
/// <summary> /// Decrypts binary data /// </summary> /// <param name="Id">Id attribute</param> /// <param name="Type">Type attribute</param> /// <param name="From">From attribute</param> /// <param name="To">To attribute</param> /// <param name="Data">Binary data to decrypt</param> /// <param name="Sender">Remote endpoint performing the encryption.</param> /// <param name="Receiver">Local endpoint performing the decryption.</param> /// <returns>Decrypted data</returns> public virtual byte[] Decrypt(string Id, string Type, string From, string To, byte[] Data, IE2eEndpoint Sender, IE2eEndpoint Receiver) { if (Data.Length < 8) { return(null); } int SignatureLen; int KeyLen; int DataLen; uint Counter; int i = 0; if (Receiver.SupportsSignatures) { SignatureLen = Data[i++]; } else { SignatureLen = 0; } if (Receiver.SupportsSharedSecrets) { KeyLen = 0; } else { KeyLen = Data[i++]; KeyLen |= Data[i++] << 8; } if (i + 4 > Data.Length) { return(null); } DataLen = Data[i++]; DataLen |= Data[i++] << 8; DataLen |= Data[i++] << 16; DataLen |= Data[i++] << 24; Counter = Data[i++]; Counter |= (uint)(Data[i++] << 8); Counter |= (uint)(Data[i++] << 16); Counter |= (uint)(Data[i++] << 24); if (Data.Length != i + SignatureLen + KeyLen + DataLen) { return(null); } byte[] Signature = new byte[SignatureLen]; byte[] EncryptedKey = KeyLen > 0 ? new byte[KeyLen] : null; byte[] Encrypted = new byte[DataLen]; byte[] Key; Array.Copy(Data, i, Signature, 0, SignatureLen); i += SignatureLen; if (KeyLen > 0) { Array.Copy(Data, i, EncryptedKey, 0, KeyLen); i += KeyLen; } Array.Copy(Data, i, Encrypted, 0, DataLen); if (EncryptedKey is null) { Key = Receiver.GetSharedSecret(Sender); } else { Key = Receiver.DecryptSecret(EncryptedKey); } byte[] Decrypted; byte[] IV = this.GetIV(Id, Type, From, To, Counter); byte[] AssociatedData = this.AuthenticatedEncryption ? Encoding.UTF8.GetBytes(From) : null; try { Decrypted = this.Decrypt(Encrypted, Key, IV, AssociatedData); if (Decrypted != null && ((Sender.SupportsSignatures && Sender.Verify(Decrypted, Signature)) || (!Sender.SupportsSignatures && SignatureLen == 0))) { return(Decrypted); } } catch (Exception) { // Invalid key } if (!(Receiver.Previous is null)) { try { if (EncryptedKey is null) { Key = Receiver.Previous.GetSharedSecret(Sender); } else { Key = Receiver.Previous.DecryptSecret(EncryptedKey); } if (!(Key is null)) { Decrypted = this.Decrypt(Encrypted, Key, IV, AssociatedData); if (Decrypted != null && ((Sender.SupportsSignatures && Sender.Verify(Decrypted, Signature)) || (!Sender.SupportsSignatures && SignatureLen == 0))) { return(Decrypted); } } } catch (Exception) { // Invalid key } } return(null); }
/// <summary> /// Gets a shared secret /// </summary> /// <param name="RemoteEndpoint">Remote endpoint</param> /// <returns>Shared secret.</returns> public override byte[] GetSharedSecret(IE2eEndpoint RemoteEndpoint) { return(GetSharedKey(this, RemoteEndpoint)); }
/// <summary> /// Shared secret, for underlying AES cipher. /// </summary> public static byte[] GetSharedKey(EllipticCurveEndpoint LocalKey, IE2eEndpoint RemoteKey) { string Key = LocalKey.PublicKeyBase64 + ";" + RemoteKey.PublicKeyBase64; if (sharedSecrets.TryGetValue(Key, out byte[] SharedKey))
/// <summary> /// Signs files using an asymmetric cipher. /// /// Command line switches: /// /// -c NAME Creates a new cipher object with random keys, /// given the name of the cipher. /// -l Lists supported cipher names. /// -keys Exports keys of selected cipher object. /// -pub KEY Creates a new cipher object of the same type as /// the current one, using a public key. Such a /// cipher object can be used for validating /// signatures. /// -priv KEY Creates a new cipher object of the same type as /// the current one, using a private key. Such a /// cipher can be used to create signatures. /// -o FILENAME Directs output to the XML file FILENAME. /// -s FILENAME Signs a file with the given filename. /// FILENAME can contain wildcards. This will /// generate one signature per file. /// -r If recursive search for files is to be used. /// -v FILENAME SIGNATURE Validates a signature for the selected file. /// -? Help. /// </summary> static int Main(string[] args) { IE2eEndpoint Endpoint = null; string OutputFileName = null; string CurrentDirectory = Directory.GetCurrentDirectory(); string s; byte[] Bin, Bin2; XmlWriter Output = null; int i = 0; int c = args.Length; bool Help = false; bool Recursive = false; try { Types.Initialize( typeof(Program).Assembly, typeof(IE2eEndpoint).Assembly, typeof(EndpointSecurity).Assembly, typeof(Security.EllipticCurves.EllipticCurve).Assembly); while (i < c) { s = args[i++].ToLower(); switch (s) { case "-c": if (i >= c) { throw new Exception("Missing cipher name."); } s = args[i++]; if (!EndpointSecurity.TryCreateEndpoint(s, EndpointSecurity.IoTHarmonizationE2E, out Endpoint)) { throw new Exception("Algorithm not recognized: " + s); } break; case "-l": foreach (Type T in Types.GetTypesImplementingInterface(typeof(IE2eEndpoint))) { TypeInfo TI = T.GetTypeInfo(); if (TI.IsAbstract) { continue; } try { using (IE2eEndpoint Endpoint2 = (IE2eEndpoint)Activator.CreateInstance(T)) { if (Endpoint2.Namespace == EndpointSecurity.IoTHarmonizationE2E) { if (Output is null) { Console.Out.WriteLine(Endpoint2.LocalName); } else { Output.WriteElementString("Cipher", Namespace, Endpoint2.LocalName); } } } } catch (Exception) { continue; } } break; case "-keys": if (Endpoint is null) { throw new Exception("No cipher has been selected."); } if (Output is null) { Console.Out.WriteLine("Public Key: " + Endpoint.PublicKeyBase64); } else { Output.WriteElementString("PublicKey", Namespace, Endpoint.PublicKeyBase64); } if (Endpoint is EllipticCurveEndpoint EC) { s = EC.Curve.Export(); XmlDocument Doc = new XmlDocument() { PreserveWhitespace = true }; Doc.LoadXml(s); s = Doc.DocumentElement.GetAttribute("d"); } else if (Endpoint is RsaEndpoint Rsa) { Bin = Rsa.Export(true); s = Convert.ToBase64String(Bin); } else { break; } if (Output is null) { Console.Out.WriteLine("Private Key: " + s); } else { Output.WriteElementString("PrivateKey", Namespace, s); } break; case "-pub": if (Endpoint is null) { throw new Exception("No cipher has been selected."); } if (i >= c) { throw new Exception("Missing public key."); } s = args[i++]; try { Bin = Convert.FromBase64String(s); } catch (Exception) { throw new Exception("Invalid public key."); } Endpoint = Endpoint.CreatePublic(Bin); break; case "-priv": if (Endpoint is null) { throw new Exception("No cipher has been selected."); } if (i >= c) { throw new Exception("Missing private key."); } s = args[i++]; try { Bin = Convert.FromBase64String(s); } catch (Exception) { throw new Exception("Invalid private key."); } Endpoint = Endpoint.CreatePrivate(Bin); break; case "-o": if (i >= c) { throw new Exception("Missing output file name."); } if (string.IsNullOrEmpty(OutputFileName)) { OutputFileName = args[i++]; } else { throw new Exception("Only one output file name allowed."); } XmlWriterSettings Settings = new XmlWriterSettings() { CloseOutput = true, ConformanceLevel = ConformanceLevel.Document, Encoding = Encoding.UTF8, Indent = true, IndentChars = "\t", NewLineChars = "\r\n", NewLineHandling = NewLineHandling.Entitize, NewLineOnAttributes = false, OmitXmlDeclaration = false, WriteEndDocumentOnClose = true, NamespaceHandling = NamespaceHandling.OmitDuplicates }; Output = XmlWriter.Create(OutputFileName, Settings); Output.WriteStartDocument(); Output.WriteStartElement("Signatures", Namespace); break; case "-s": if (Endpoint is null) { throw new Exception("No cipher has been selected."); } if (i >= c) { throw new Exception("Missing input file name."); } s = args[i++]; string[] FileNames; if (s.Contains("*") || s.Contains("?")) { s = Path.Combine(CurrentDirectory, s); string FileName = Path.GetFileName(s); string Folder = Path.GetDirectoryName(s); FileNames = Directory.GetFiles(Folder, FileName, Recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly); } else { FileNames = new string[] { s } }; foreach (string FileName in FileNames) { using (FileStream f = File.OpenRead(FileName)) { Bin = Endpoint.Sign(f); } s = Convert.ToBase64String(Bin); if (Output is null) { Console.Out.WriteLine("Signature: " + s); } else { Output.WriteStartElement("Signature"); Output.WriteAttributeString("fileName", Path.GetRelativePath(CurrentDirectory, FileName)); Output.WriteValue(s); Output.WriteEndElement(); } } break; case "-v": if (Endpoint is null) { throw new Exception("No cipher has been selected."); } if (i >= c) { throw new Exception("Missing input file name."); } s = args[i++]; Bin = File.ReadAllBytes(s); if (i >= c) { throw new Exception("Missing signature."); } try { Bin2 = Convert.FromBase64String(args[i++]); } catch (Exception) { throw new Exception("Invalid signature."); } bool Valid = Endpoint.Verify(Bin, Bin2); if (Output is null) { Console.Out.WriteLine("Valid: " + Valid.ToString()); } else { Output.WriteStartElement("Valid"); Output.WriteAttributeString("fileName", Path.GetRelativePath(CurrentDirectory, s)); Output.WriteValue(Valid ? "true" : "false"); Output.WriteEndElement(); } break; case "-?": Help = true; break; case "-r": Recursive = true; break; default: throw new Exception("Unrecognized switch: " + s); } } if (Help || c == 0) { Console.Out.WriteLine("Signs files using an asymmetric cipher."); Console.Out.WriteLine(); Console.Out.WriteLine("Command line switches:"); Console.Out.WriteLine(); Console.Out.WriteLine("-c NAME Creates a new cipher object with random keys,"); Console.Out.WriteLine(" given the name of the cipher."); Console.Out.WriteLine("-l Lists supported cipher names."); Console.Out.WriteLine("-keys Exports keys of selected cipher object."); Console.Out.WriteLine("-pub KEY Creates a new cipher object of the same type as"); Console.Out.WriteLine(" the current one, using a public key. Such a"); Console.Out.WriteLine(" cipher object can be used for validating"); Console.Out.WriteLine(" signatures."); Console.Out.WriteLine("-priv KEY Creates a new cipher object of the same type as"); Console.Out.WriteLine(" the current one, using a private key. Such a"); Console.Out.WriteLine(" cipher can be used to create signatures."); Console.Out.WriteLine("-o FILENAME Directs output to the XML file FILENAME."); Console.Out.WriteLine("-s FILENAME Signs a file with the given filename."); Console.Out.WriteLine(" FILENAME can contain wildcards. This will"); Console.Out.WriteLine(" generate one signature per file."); Console.Out.WriteLine("-r If recursive search for files is to be used."); Console.Out.WriteLine("-v FILENAME SIGNATURE Validates a signature for the selected file."); Console.Out.WriteLine("-? Help."); } return(0); } catch (Exception ex) { Console.Out.WriteLine(ex.Message); return(-1); } finally { Output?.WriteEndElement(); Output?.WriteEndDocument(); Output?.Dispose(); } }
/// <summary> /// Event arguments for key responses /// </summary> /// <param name="Key">Key.</param> /// <param name="State">State object.</param> public KeyEventArgs(IE2eEndpoint Key, object State) : base(new IqResultEventArgs(null, string.Empty, string.Empty, string.Empty, true, State)) { this.key = Key; }
/// <summary> /// Parses an identity from its XML representation /// </summary> /// <param name="Xml">XML representation</param> /// <returns>Legal identity</returns> public static LegalIdentity Parse(XmlElement Xml) { List <Property> Properties = new List <Property>(); List <Attachment> Attachments = new List <Attachment>(); LegalIdentity Result = new LegalIdentity() { id = XML.Attribute(Xml, "id") }; foreach (XmlNode N in Xml.ChildNodes) { if (N is XmlElement E) { switch (E.LocalName) { case "clientPublicKey": foreach (XmlNode N2 in E.ChildNodes) { if (N2 is XmlElement E2) { IE2eEndpoint Key = EndpointSecurity.ParseE2eKey(E2); if (Key != null && Key.Namespace == EndpointSecurity.IoTHarmonizationE2E) { Result.clientPubKey = Key.PublicKey; if (Key is RsaEndpoint RsaEndpoint) { Result.clientKeyName = "RSA" + RsaEndpoint.KeySize.ToString(); } else { Result.clientKeyName = Key.LocalName; } } } } break; case "property": string Name = XML.Attribute(E, "name"); string Value = XML.Attribute(E, "value"); Properties.Add(new Property(Name, Value)); break; case "clientSignature": Result.clientSignature = Convert.FromBase64String(E.InnerText); break; case "attachment": Attachments.Add(new Attachment() { Id = XML.Attribute(E, "id"), LegalId = Result.id, ContentType = XML.Attribute(E, "contentType"), FileName = XML.Attribute(E, "fileName"), Signature = Convert.FromBase64String(XML.Attribute(E, "s")), Timestamp = XML.Attribute(E, "timestamp", DateTime.MinValue) }); break; case "status": foreach (XmlAttribute Attr in E.Attributes) { switch (Attr.Name) { case "provider": Result.provider = Attr.Value; break; case "state": if (Enum.TryParse <IdentityState>(Attr.Value, out IdentityState IdentityState)) { Result.state = IdentityState; } break; case "created": if (XML.TryParse(Attr.Value, out DateTime TP)) { Result.created = TP; } break; case "updated": if (XML.TryParse(Attr.Value, out TP)) { Result.updated = TP; } break; case "from": if (XML.TryParse(Attr.Value, out TP)) { Result.from = TP; } break; case "to": if (XML.TryParse(Attr.Value, out TP)) { Result.to = TP; } break; } } break; case "serverSignature": Result.serverSignature = Convert.FromBase64String(E.InnerText); break; case "attachmentRef": string AttachmentId = XML.Attribute(E, "attachmentId"); string Url = XML.Attribute(E, "url"); foreach (Attachment Attachment in Attachments) { if (Attachment.Id == AttachmentId) { Attachment.Url = Url; break; } } break; } } } Result.properties = Properties.ToArray(); Result.attachments = Attachments.ToArray(); return(Result); }
/// <summary> /// Decrypts binary data /// </summary> /// <param name="Id">Id attribute</param> /// <param name="Type">Type attribute</param> /// <param name="From">From attribute</param> /// <param name="To">To attribute</param> /// <param name="Data">Binary data to decrypt</param> /// <param name="Sender">Remote endpoint performing the encryption.</param> /// <param name="Receiver">Local endpoint performing the decryption.</param> /// <returns>Decrypted data, if able, null otherwise.</returns> public virtual async Task <Stream> Decrypt(string Id, string Type, string From, string To, Stream Data, IE2eEndpoint Sender, IE2eEndpoint Receiver) { if (Data.Length < 8) { return(null); } int SignatureLen; int KeyLen; int DataLen; uint Counter; if (Receiver.SupportsSignatures) { SignatureLen = Data.ReadByte(); if ((SignatureLen & 128) != 0) { SignatureLen &= 127; SignatureLen |= Data.ReadByte() << 7; } } else { SignatureLen = 0; } if (Receiver.SupportsSharedSecrets) { KeyLen = 0; } else { KeyLen = Data.ReadByte(); KeyLen |= Data.ReadByte() << 8; } if (Data.Position + 4 > Data.Length) { return(null); } DataLen = Data.ReadByte(); DataLen |= Data.ReadByte() << 8; DataLen |= Data.ReadByte() << 16; DataLen |= Data.ReadByte() << 24; Counter = (byte)Data.ReadByte(); Counter |= (uint)(Data.ReadByte() << 8); Counter |= (uint)(Data.ReadByte() << 16); Counter |= (uint)(Data.ReadByte() << 24); if (Data.Length != Data.Position + SignatureLen + KeyLen + DataLen) { return(null); } byte[] Signature = new byte[SignatureLen]; byte[] EncryptedKey = KeyLen > 0 ? new byte[KeyLen] : null; byte[] Key; if (await Data.ReadAsync(Signature, 0, SignatureLen) != SignatureLen) { return(null); } if (KeyLen > 0) { if (await Data.ReadAsync(EncryptedKey, 0, KeyLen) != KeyLen) { return(null); } } using (TemporaryStream Encrypted = new TemporaryStream()) { await Crypto.CopyAsync(Data, Encrypted, DataLen); if (EncryptedKey is null) { Key = Receiver.GetSharedSecret(Sender); } else { Key = Receiver.DecryptSecret(EncryptedKey); } byte[] IV = this.GetIV(Id, Type, From, To, Counter); byte[] AssociatedData = this.AuthenticatedEncryption ? Encoding.UTF8.GetBytes(From) : null; Stream Decrypted = null; try { Encrypted.Position = 0; Decrypted = await this.Decrypt(Encrypted, Key, IV, AssociatedData); if (!(Decrypted is null)) { Decrypted.Position = 0; if ((Sender.SupportsSignatures && Sender.Verify(Decrypted, Signature)) || (!Sender.SupportsSignatures && SignatureLen == 0)) { return(Decrypted); } Decrypted.Dispose(); Decrypted = null; } } catch (Exception) { // Invalid key Decrypted?.Dispose(); Decrypted = null; } if (!(Receiver.Previous is null)) { try { if (EncryptedKey is null) { Key = Receiver.Previous.GetSharedSecret(Sender); } else { Key = Receiver.Previous.DecryptSecret(EncryptedKey); } if (!(Key is null)) { Encrypted.Position = 0; Decrypted = await this.Decrypt(Encrypted, Key, IV, AssociatedData); if (!(Decrypted is null)) { Decrypted.Position = 0; if ((Sender.SupportsSignatures && Sender.Verify(Decrypted, Signature)) || (!Sender.SupportsSignatures && SignatureLen == 0)) { return(Decrypted); } Decrypted.Dispose(); Decrypted = null; } } } catch (Exception) { // Invalid key Decrypted?.Dispose(); Decrypted = null; } } return(null); } }
/// <summary> /// Encrypts binary data /// </summary> /// <param name="Id">Id attribute</param> /// <param name="Type">Type attribute</param> /// <param name="From">From attribute</param> /// <param name="To">To attribute</param> /// <param name="Counter">Counter. Can be reset every time a new key is generated. /// A new key must be generated before the counter wraps.</param> /// <param name="Data">Binary data to encrypt</param> /// <param name="Sender">Local endpoint performing the encryption.</param> /// <param name="Receiver">Remote endpoint performing the decryption.</param> /// <returns>Encrypted data</returns> public virtual byte[] Encrypt(string Id, string Type, string From, string To, uint Counter, byte[] Data, IE2eEndpoint Sender, IE2eEndpoint Receiver) { byte[] Encrypted; byte[] EncryptedKey; byte[] Key; byte[] IV = this.GetIV(Id, Type, From, To, Counter); byte[] AssociatedData = this.AuthenticatedEncryption ? Encoding.UTF8.GetBytes(From) : null; byte[] Signature; byte[] Block; int i, j, k, l; int c = 8; if (Sender.SupportsSharedSecrets) { Key = Sender.GetSharedSecret(Receiver); EncryptedKey = null; l = 0; } else { Key = this.GenerateKey(); EncryptedKey = Receiver.EncryptSecret(Key); l = EncryptedKey.Length; c += l + 1; } Encrypted = this.Encrypt(Data, Key, IV, AssociatedData); i = Encrypted.Length; j = 0; c += i; if (Sender.SupportsSignatures) { Signature = Sender.Sign(Data); k = Signature.Length; c += k + 1; } else { k = 0; Signature = null; } Block = new byte[c]; if (k > 0) { Block[j++] = (byte)k; } if (l > 0) { Block[j++] = (byte)l; Block[j++] = (byte)(l >> 8); } Block[j++] = (byte)i; Block[j++] = (byte)(i >> 8); Block[j++] = (byte)(i >> 16); Block[j++] = (byte)(i >> 24); Block[j++] = (byte)Counter; Block[j++] = (byte)(Counter >> 8); Block[j++] = (byte)(Counter >> 16); Block[j++] = (byte)(Counter >> 24); if (k > 0) { Array.Copy(Signature, 0, Block, j, k); j += k; } if (l > 0) { Array.Copy(EncryptedKey, 0, Block, j, l); j += l; } Array.Copy(Encrypted, 0, Block, j, i); return(Block); }
/// <summary> /// Encrypts binary data /// </summary> /// <param name="Id">Id attribute</param> /// <param name="Type">Type attribute</param> /// <param name="From">From attribute</param> /// <param name="To">To attribute</param> /// <param name="Data">Binary data to encrypt</param> /// <param name="LocalEndpoint">Local endpoint of same type.</param> /// <returns>Encrypted data</returns> public override byte[] Encrypt(string Id, string Type, string From, string To, byte[] Data, IE2eEndpoint LocalEndpoint) { byte[] Result; byte[] KeyEncrypted; byte[] Signature; byte[] IV = GetIV(Id, Type, From, To); lock (this.rsa) { this.aes.GenerateKey(); this.aes.IV = IV; KeyEncrypted = this.rsa.Encrypt(this.aes.Key, RSAEncryptionPadding.OaepSHA256); Result = this.Encrypt(Data, this.aes.Key, IV); } Signature = (LocalEndpoint as RsaAes)?.Sign(Data); if (Signature == null) { return(null); } byte[] Block = new byte[KeyEncrypted.Length + Signature.Length + Result.Length + 8]; int i, j; j = 8; i = KeyEncrypted.Length; Array.Copy(KeyEncrypted, 0, Block, j, i); j += i; Block[0] = (byte)(i >> 8); Block[1] = (byte)i; i = Signature.Length; Array.Copy(Signature, 0, Block, j, i); j += i; Block[2] = (byte)(i >> 8); Block[3] = (byte)i; i = Result.Length; Array.Copy(Result, 0, Block, j, i); j += i; Block[4] = (byte)(i >> 24); Block[5] = (byte)(i >> 16); Block[6] = (byte)(i >> 8); Block[7] = (byte)i; return(Block); }
/// <summary> /// Decrypts binary data /// </summary> /// <param name="Id">Id attribute</param> /// <param name="Type">Type attribute</param> /// <param name="From">From attribute</param> /// <param name="To">To attribute</param> /// <param name="Data">Binary data to decrypt</param> /// <param name="RemoteEndpoint">Remote endpoint of same type.</param> /// <returns>Decrypted data</returns> public override byte[] Decrypt(string Id, string Type, string From, string To, byte[] Data, IE2eEndpoint RemoteEndpoint) { if (!(RemoteEndpoint is RsaAes RemoteRsaAes)) { return(null); } if (Data.Length < 10) { return(null); } int KeyLen; int SignatureLen; int DataLen; KeyLen = Data[0]; KeyLen <<= 8; KeyLen |= Data[1]; SignatureLen = Data[2]; SignatureLen <<= 8; SignatureLen |= Data[3]; DataLen = Data[4]; DataLen <<= 8; DataLen |= Data[5]; DataLen <<= 8; DataLen |= Data[6]; DataLen <<= 8; DataLen |= Data[7]; if (Data.Length != 8 + KeyLen + SignatureLen + DataLen) { return(null); } byte[] KeyEncrypted = new byte[KeyLen]; byte[] Signature = new byte[SignatureLen]; byte[] Encrypted = new byte[DataLen]; int i = 10; Array.Copy(Data, i, KeyEncrypted, 0, KeyLen); i += KeyLen; Array.Copy(Data, i, Signature, 0, SignatureLen); i += SignatureLen; Array.Copy(Data, i, Encrypted, 0, DataLen); i += DataLen; byte[] Decrypted; byte[] Key; byte[] IV = GetIV(Id, Type, From, To); try { Key = this.Decrypt(KeyEncrypted); Decrypted = this.Decrypt(Encrypted, Key, IV); } catch (Exception) { Decrypted = null; } if (Decrypted == null) { try { Key = (this.Previous as RsaAes)?.Decrypt(KeyEncrypted); if (Key != null && IV != null) { Decrypted = this.Decrypt(Encrypted, Key, IV); if (Decrypted == null) { return(null); } } else { return(null); } } catch (Exception) { return(null); // Invalid keys. } } lock (RemoteRsaAes.rsa) { if (!RemoteRsaAes.rsa.VerifyData(Decrypted, Signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pss)) { return(null); } } return(Decrypted); }
/// <summary> /// Encrypts Binary data /// </summary> /// <param name="Id">Id attribute</param> /// <param name="Type">Type attribute</param> /// <param name="From">From attribute</param> /// <param name="To">To attribute</param> /// <param name="Data">Binary data to encrypt</param> /// <param name="Xml">XML output</param> /// <param name="LocalEndpoint">Local endpoint of same type.</param> /// <returns>If encryption was possible</returns> public override bool Encrypt(string Id, string Type, string From, string To, byte[] Data, StringBuilder Xml, IE2eEndpoint LocalEndpoint) { byte[] Result; byte[] KeyEncrypted; byte[] Signature; byte[] IV = GetIV(Id, Type, From, To); lock (this.rsa) { this.aes.GenerateKey(); this.aes.IV = IV; KeyEncrypted = this.rsa.Encrypt(this.aes.Key, RSAEncryptionPadding.OaepSHA256); Result = this.Encrypt(Data, this.aes.Key, IV); } Signature = (LocalEndpoint as RsaAes)?.Sign(Data); if (Signature == null) { return(false); } Xml.Append("<aes xmlns=\""); Xml.Append(EndpointSecurity.IoTHarmonizationE2E); Xml.Append("\" keyRsa=\""); Xml.Append(Convert.ToBase64String(KeyEncrypted)); Xml.Append("\" signRsa=\""); Xml.Append(Convert.ToBase64String(Signature)); Xml.Append("\">"); Xml.Append(Convert.ToBase64String(Result)); Xml.Append("</aes>"); return(true); }
/// <summary> /// Gets a shared secret /// </summary> /// <param name="RemoteEndpoint">Remote endpoint</param> /// <returns>Shared secret.</returns> public override byte[] GetSharedSecret(IE2eEndpoint RemoteEndpoint) { throw new NotSupportedException("Getting shared secrets using RSA not supported."); }
/// <summary> /// Event arguments for signature responses /// </summary> /// <param name="Key">Key algorithm used.</param> /// <param name="Signature">Digital signature</param> /// <param name="State">State object.</param> public SignatureEventArgs(IE2eEndpoint Key, byte[] Signature, object State) : base(new KeyEventArgs(Key, State)) { this.signature = Signature; }