private SqrlMessage PrepareMessage(Uri uri) { string site = uri.Host; int additionalDomainsChars = GetAdditionalDomainChars(uri); if (additionalDomainsChars > 1 && additionalDomainsChars <= uri.LocalPath.Length) { site += uri.LocalPath.Substring(0, additionalDomainsChars); } byte[] siteKey = _identity.GetSitePrivateKey(site); var keys = CryptoSign.GenerateKeyPair(siteKey); var message = new SqrlMessage { PublicKeyBase64 = Convert.ToBase64String(keys.PublicKey) }; StringBuilder url = new StringBuilder(uri.ToString()); if (string.IsNullOrEmpty(uri.Query)) { url.Append("?"); } else if (!uri.Query.EndsWith("?") && !uri.Query.EndsWith("&")) { url.Append("&"); } url.Append("sqrlver=").Append(SqrlVersion); url.Append("&sqrlkey=").Append(UrlSafeBase64Encoder.Encode(message.PublicKeyBase64)); message.Uri = new Uri(url.ToString()); var idn = new IdnMapping(); var puny = idn.GetAscii(message.Uri.ToString()); byte[] urlBytes = Encoding.ASCII.GetBytes(puny); byte[] signed = CryptoSign.Sign(urlBytes, keys.SecretKey); // The signature is only the first 64 bytes, the rest is the message Array.Resize(ref signed, 64); message.SignatureBase64 = Convert.ToBase64String(signed); return(message); }
private static void VerifyMessage(SqrlMessage sqrl) { string url = sqrl.Uri.ToString() .Replace("https://", "sqrl://") .Replace("http://", "qrl://"); var idn = new IdnMapping(); var puny = idn.GetAscii(url); var punyBytes = Encoding.ASCII.GetBytes(puny); var signatureBytes = sqrl.SignatureBytes; var signature = new byte[punyBytes.Length + signatureBytes.Length]; Buffer.BlockCopy(signatureBytes, 0, signature, 0, signatureBytes.Length); Buffer.BlockCopy(punyBytes, 0, signature, signatureBytes.Length, punyBytes.Length); if (!CryptoSign.Open(signature, sqrl.PublicKeyBytes)) { throw new SqrlAuthenticationException("Signature verification failed."); } }