/// <summary> /// Verifies that a digital signature is valid by calculating the hash value of the specified data /// using the specified hash algorithm and padding, and comparing it to the provided signature. /// </summary> /// <param name="data">The data to sign.</param> /// <param name="signature">The signature data to be verified.</param> /// <returns>true if the signature is valid; otherwise, false.</returns> public bool Verify(byte[] data, byte[] signature) { return(ListExtensions.Equals(Sign(data), signature)); }
/// <summary> /// Verifies that a digital signature is valid by calculating the hash value of the specified data /// using the specified hash algorithm and padding, and comparing it to the provided signature. /// </summary> /// <param name="data">The data to sign.</param> /// <param name="signature">The signature data to be verified.</param> /// <returns>true if the signature is valid; otherwise, false.</returns> public bool Verify(byte[] data, byte[] signature) { return(verify != null ? verify(data, signature, secretBytes) : ListExtensions.Equals(sign(data, secretBytes), signature)); }
/// <summary> /// Parses the parameters from OpenSSL RSA key (PEM Base64) or the RSA parameters XML string. /// </summary> /// <param name="key">The OpenSSL RSA key string (PEM Base64) or the RSA parameters XML string.</param> /// <returns>The RSA parameters; or null, if parse failed.</returns> public static RSAParameters?Parse(string key) { if (string.IsNullOrWhiteSpace(key)) { return(null); } key = key.Trim(); if (key.IndexOf("<") == 0 && key.LastIndexOf(">") == key.Length - 1) { var xml = XElement.Parse(key); if (xml == null) { return(null); } var p = new RSAParameters(); foreach (var ele in xml.Elements()) { if (string.IsNullOrWhiteSpace(ele?.Value)) { continue; } var chars = Convert.FromBase64String(ele.Value); switch (ele.Name?.LocalName?.ToLowerInvariant()) { case "modulus": p.Modulus = chars; break; case "exponent": p.Exponent = chars; break; case "p": p.P = chars; break; case "q": p.Q = chars; break; case "dp": p.DP = chars; break; case "dq": p.DQ = chars; break; case "inverseq": p.InverseQ = chars; break; case "d": p.D = chars; break; } } if (p.Modulus == null || p.Modulus.Length == 0 || p.Exponent == null || p.Exponent.Length == 0) { return(null); } return(p); } var lines = key.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); if (lines.Length == 0) { return(null); } var isPrivate = true; var firstLine = lines[0].Trim(); if (lines.Length == 1) { key = firstLine; } else if (firstLine.IndexOf("ssh-rsa ") == 0) { isPrivate = false; key = string.Join(string.Empty, lines).Trim(); if (key.Length < 16) { return(null); } key = key.Substring(8); var blankPos = key.IndexOf(' '); if (blankPos > 0) { key = key.Substring(0, blankPos); } } else if (lines.Length == 2) { isPrivate = firstLine.IndexOf("PRIVATE KEY") >= 0; key = lines[1]; } else { isPrivate = firstLine.IndexOf(" PRIVATE KEY") > 0 || firstLine.IndexOf("PRIVATE KEY") == 0; key = string.Join(string.Empty, lines.Skip(1).Take(lines.Length - 2)); } using (var stream = new MemoryStream(Convert.FromBase64String(key))) { using (var reader = new BinaryReader(stream)) { if (isPrivate) { var twoBytes = reader.ReadUInt16(); if (twoBytes == 0x8130) { reader.ReadByte(); } else if (twoBytes == 0x8230) { reader.ReadInt16(); } else { return(null); } if (!AreSame(reader, verPem)) { return(null); } // For PKCS8. if (reader.BaseStream.Position + seqOID.Length < reader.BaseStream.Length) { var isPkcs8 = true; var i = 0; for (; i < seqOID.Length; i++) { if (seqOID[i] == reader.ReadByte()) { continue; } isPkcs8 = false; break; } if (isPkcs8) { GetIntegerSize(reader, 0x04); GetIntegerSize(reader, 0x30); if (!AreSame(reader, verPem)) { return(null); } } else { i++; reader.BaseStream.Seek(-i, SeekOrigin.Current); } } return(new RSAParameters { Modulus = reader.ReadBytes(GetIntegerSize(reader)), Exponent = reader.ReadBytes(GetIntegerSize(reader)), D = reader.ReadBytes(GetIntegerSize(reader)), P = reader.ReadBytes(GetIntegerSize(reader)), Q = reader.ReadBytes(GetIntegerSize(reader)), DP = reader.ReadBytes(GetIntegerSize(reader)), DQ = reader.ReadBytes(GetIntegerSize(reader)), InverseQ = reader.ReadBytes(GetIntegerSize(reader)) }); } else { var twoBytes = reader.ReadUInt16(); if (twoBytes == 0x8130) // Data read as little endian order (actual data order for Sequence is 30 81). { reader.ReadByte(); // Advance 1 byte. } else if (twoBytes == 0x8230) { reader.ReadInt16(); // Advance 2 bytes. } else { return(null); } var seq = reader.ReadBytes(15); // Read the Sequence OID. if (!ListExtensions.Equals(seq, seqOID)) // Make sure Sequence for OID is correct. { return(null); } twoBytes = reader.ReadUInt16(); if (twoBytes == 0x8103) // Data read as little endian order (actual data order for Bit String is 03 81). { reader.ReadByte(); // Advance 1 byte. } else if (twoBytes == 0x8203) { reader.ReadInt16(); // Advance 2 bytes. } else { return(null); } var testByte = reader.ReadByte(); if (testByte != 0x00) // Expect null byte next. { return(null); } twoBytes = reader.ReadUInt16(); if (twoBytes == 0x8130) // Data read as little endian order (actual data order for Sequence is 30 81). { reader.ReadByte(); // Advance 1 byte. } else if (twoBytes == 0x8230) { reader.ReadInt16(); // Advance 2 bytes. } else { return(null); } twoBytes = reader.ReadUInt16(); byte lowByte = 0x00; byte highByte = 0x00; if (twoBytes == 0x8102) // Data read as little endian order (actual data order for Integer is 02 81). { lowByte = reader.ReadByte(); // Read next bytes which is bytes in modulus. } else if (twoBytes == 0x8202) { highByte = reader.ReadByte(); // Advance 2 bytes. lowByte = reader.ReadByte(); } else { return(null); } byte[] modInt = { lowByte, highByte, 0x00, 0x00 }; // Reverse byte order since asn.1 key uses big endian order. var modsize = BitConverter.ToInt32(modInt, 0); var firstByte = reader.PeekChar(); if (firstByte == 0x00) { // Don't include it if the first byte (highest order) of modulus is zero. reader.ReadByte(); // Skip this null byte. modsize -= 1; // Reduce modulus buffer size by 1. } var modulus = reader.ReadBytes(modsize); // Read the modulus bytes. if (reader.ReadByte() != 0x02) // Expect an Integer for the exponent data. { return(null); } var expBytes = (int)reader.ReadByte(); // Should only need one byte for actual exponent data (for all useful values). var exponent = reader.ReadBytes(expBytes); // Create RSACryptoServiceProvider instance and initialize with public key. return(new RSAParameters { Modulus = modulus, Exponent = exponent }); } } } }