/// <summary> /// Validates a client signature /// </summary> /// <param name="Data">Binary data being signed.</param> /// <param name="Signature">Digital signature</param> /// <returns>If the client signature is correct</returns> public bool ValidateSignature(byte[] Data, byte[] Signature) { if (!this.HasClientPublicKey) { return(false); } if (this.clientKeyName.StartsWith("RSA")) { if (!int.TryParse(this.clientKeyName.Substring(3), out int KeySize)) { return(false); } return(RsaEndpoint.Verify(Data, Signature, KeySize, this.clientPubKey)); } else if (EndpointSecurity.TryCreateEndpoint(this.clientKeyName, EndpointSecurity.IoTHarmonizationE2E, out IE2eEndpoint Endpoint) && Endpoint is EllipticCurveEndpoint LocalEc) { return(LocalEc.Verify(Data, this.clientPubKey, Signature)); } else { return(false); } }
/// <summary> /// Validates a client signature /// </summary> /// <param name="Data">Binary data being signed.</param> /// <param name="s1">First signature</param> /// <param name="s2">Second signature, if available.</param> /// <returns>If the client signature is correct</returns> public bool ValidateSignature(byte[] Data, byte[] s1, byte[] s2) { if (!this.HasClientPublicKey) { return(false); } if (this.clientKeyName.StartsWith("RSA")) { if (!int.TryParse(this.clientKeyName.Substring(3), out int KeySize)) { return(false); } return(RsaAes.Verify(Data, s1, KeySize, this.clientPubKey1, this.clientPubKey2)); } else if (EndpointSecurity.TryCreateEndpoint(this.clientKeyName, EndpointSecurity.IoTHarmonizationE2E, out IE2eEndpoint Endpoint) && Endpoint is EcAes256 EcAes256) { if (s2 == null) { return(false); } return(EcAes256.Verify(Data, this.clientPubKey1, this.clientPubKey2, s1, s2, HashFunction.SHA256)); } else { return(false); } }
/// <summary> /// RSA / AES-256 hybrid cipher. /// </summary> /// <param name="KeySize">Size of key</param> /// <param name="Modulus">Modulus of RSA public key.</param> /// <param name="Exponent">Exponent of RSA public key.</param> /// <param name="LocalEndpoint">Local security endpoint, if available.</param> public RsaAes(int KeySize, byte[] Modulus, byte[] Exponent, EndpointSecurity LocalEndpoint) : base() { this.rsa = RSA.Create(); this.rsa.KeySize = KeySize; this.keySize = KeySize; this.modulus = Modulus; this.exponent = Exponent; this.localEndpoint = LocalEndpoint; RSAParameters Param = new RSAParameters() { Modulus = Modulus, Exponent = Exponent }; this.rsa.ImportParameters(Param); }
/// <summary> /// NIST P-224 Curve /// </summary> /// <param name="X">X-coordinate of remote public key.</param> /// <param name="Y">Y-coordinate of remote public key.</param> /// <param name="LocalEndpoint">Local security endpoint, if available.</param> public NistP224Aes(byte[] X, byte[] Y, EndpointSecurity LocalEndpoint) : base(X, Y, LocalEndpoint) { }
/// <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); }
public override void PrepareClient2(XmppClient Client) { base.PrepareClient2(Client); this.endpointSecurity2 = new EndpointSecurity(this.client2, 128, this.endpoints2); }
public override void PrepareClient1(XmppClient Client) { base.PrepareClient1(Client); this.endpointSecurity1 = new EndpointSecurity(this.client1, 128, this.endpoints1); }
/// <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> /// 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> /// Abstract base class for Elliptic Curve / AES-256 hybrid ciphers.s /// </summary> /// <param name="X">X-coordinate of remote public key.</param> /// <param name="Y">Y-coordinate of remote public key.</param> /// <param name="LocalEndpoint">Local security endpoint, if available.</param> public EcAes256(byte[] X, byte[] Y, EndpointSecurity LocalEndpoint) : base() { this.publicKey = new PointOnCurve(FromNetwork(X), FromNetwork(Y)); this.localEndpoint = LocalEndpoint; }