summaryrefslogtreecommitdiffstats
path: root/src/DotNetOpenAuth.OAuth2/OAuth2/Crypto
diff options
context:
space:
mode:
authorAndrew Arnott <andrewarnott@gmail.com>2012-04-28 19:56:30 -0700
committerAndrew Arnott <andrewarnott@gmail.com>2012-04-28 20:01:00 -0700
commitea4325d172d8a2bc925ed362f1c35560b8c1f13e (patch)
treea04960f4cddd7f2223df83b03e89300c5051434c /src/DotNetOpenAuth.OAuth2/OAuth2/Crypto
parent01d8c73f818d30b20f86630d35d230b5168215d1 (diff)
downloadDotNetOpenAuth-ea4325d172d8a2bc925ed362f1c35560b8c1f13e.zip
DotNetOpenAuth-ea4325d172d8a2bc925ed362f1c35560b8c1f13e.tar.gz
DotNetOpenAuth-ea4325d172d8a2bc925ed362f1c35560b8c1f13e.tar.bz2
Work toward support JWT access tokens.origin/jwt
Diffstat (limited to 'src/DotNetOpenAuth.OAuth2/OAuth2/Crypto')
-rw-r--r--src/DotNetOpenAuth.OAuth2/OAuth2/Crypto/JsonWebAlgorithms.cs141
-rw-r--r--src/DotNetOpenAuth.OAuth2/OAuth2/Crypto/JweHeader.cs74
-rw-r--r--src/DotNetOpenAuth.OAuth2/OAuth2/Crypto/JweRsaEncryptionAlgorithm.cs29
-rw-r--r--src/DotNetOpenAuth.OAuth2/OAuth2/Crypto/JwsHeader.cs36
-rw-r--r--src/DotNetOpenAuth.OAuth2/OAuth2/Crypto/JwtEncryptionAlgorithm.cs41
-rw-r--r--src/DotNetOpenAuth.OAuth2/OAuth2/Crypto/JwtHeader.cs16
-rw-r--r--src/DotNetOpenAuth.OAuth2/OAuth2/Crypto/JwtHmacShaSigningAlgorithm.cs84
-rw-r--r--src/DotNetOpenAuth.OAuth2/OAuth2/Crypto/JwtMessageBase.cs26
-rw-r--r--src/DotNetOpenAuth.OAuth2/OAuth2/Crypto/JwtRsaShaSigningAlgorithm.cs82
-rw-r--r--src/DotNetOpenAuth.OAuth2/OAuth2/Crypto/JwtSigningAlgorithm.cs33
10 files changed, 562 insertions, 0 deletions
diff --git a/src/DotNetOpenAuth.OAuth2/OAuth2/Crypto/JsonWebAlgorithms.cs b/src/DotNetOpenAuth.OAuth2/OAuth2/Crypto/JsonWebAlgorithms.cs
new file mode 100644
index 0000000..fea18ba
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2/OAuth2/Crypto/JsonWebAlgorithms.cs
@@ -0,0 +1,141 @@
+namespace DotNetOpenAuth.OAuth2.Crypto {
+ internal static class JsonWebSignatureAlgorithms {
+ /// <summary>
+ /// HMAC using SHA-256 hash algorithm.
+ /// </summary>
+ internal const string HmacSha256 = "HS256";
+
+ /// <summary>
+ /// HMAC using SHA-384 hash algorithm.
+ /// </summary>
+ internal const string HmacSha384 = "HS384";
+
+ /// <summary>
+ /// HMAC using SHA-512 hash algorithm.
+ /// </summary>
+ internal const string HmacSha512 = "HS512";
+
+ /// <summary>
+ /// RSA using SHA-256 hash algorithm.
+ /// </summary>
+ internal const string RsaSha256 = "RS256";
+
+ /// <summary>
+ /// RSA using SHA-384 hash algorithm.
+ /// </summary>
+ internal const string RsaSha384 = "RS384";
+
+ /// <summary>
+ /// RSA using SHA-512 hash algorithm.
+ /// </summary>
+ internal const string RsaSha512 = "RS512";
+
+ /// <summary>
+ /// ECDSA using P-256 curve and SHA-256 hash algorithm.
+ /// </summary>
+ internal const string ECDsaSha256 = "ES256";
+
+ /// <summary>
+ /// ECDSA using P-384 curve and SHA-384 hash algorithm.
+ /// </summary>
+ internal const string ECDsaSha384 = "ES384";
+
+ /// <summary>
+ /// ECDSA using P-521 curve and SHA-512 hash algorithm.
+ /// </summary>
+ internal const string ECDsaSha512 = "ES512";
+
+ /// <summary>
+ /// No digital signature or HMAC value included.
+ /// </summary>
+ internal const string None = "none";
+ }
+
+ /// <summary>
+ /// The set of alg (algorithm) header parameter values that are defined by this
+ /// specification for use with JWE. These algorithms are used to encrypt the CEK,
+ /// which produces the JWE Encrypted Key.
+ /// </summary>
+ /// <remarks>
+ /// http://self-issued.info/docs/draft-ietf-jose-json-web-algorithms-01.html#EncAlgTable
+ /// </remarks>
+ internal static class JsonWebEncryptionAlgorithms {
+ /// <summary>
+ /// RSA using RSA-PKCS1-1.5 padding, as defined in RFC 3447 [RFC3447]
+ /// </summary>
+ internal const string RSA1_5 = "RSA1_5";
+
+ /// <summary>
+ /// RSA using Optimal Asymmetric Encryption Padding (OAEP), as defined in RFC 3447 [RFC3447]
+ /// </summary>
+ internal const string RSA_OAEP = "RSA-OAEP";
+
+ /// <summary>
+ /// Elliptic Curve Diffie-Hellman Ephemeral Static, as defined in RFC 6090
+ /// [RFC6090], and using the Concat KDF, as defined in [NIST‑800‑56A],
+ /// where the Digest Method is SHA-256 and all OtherInfo parameters are
+ /// the empty bit string
+ /// </summary>
+ internal const string ECDH_ES = "ECDH-ES";
+
+ /// <summary>
+ /// Advanced Encryption Standard (AES) Key Wrap Algorithm using 128 bit keys,
+ /// as defined in RFC 3394 [RFC3394]
+ /// </summary>
+ internal const string A128KW = "A128KW";
+
+ /// <summary>
+ /// Advanced Encryption Standard (AES) Key Wrap Algorithm using 256 bit keys,
+ /// as defined in RFC 3394 [RFC3394]
+ /// </summary>
+ internal const string A256KW = "A256KW";
+
+ /// <summary>
+ /// Advanced Encryption Standard (AES) Key Wrap Algorithm using 512 bit keys,
+ /// as defined in RFC 3394 [RFC3394]
+ /// </summary>
+ internal const string A512KW = "A512KW";
+
+ /// <summary>
+ /// Advanced Encryption Standard (AES) using 128 bit keys in Galois/Counter
+ /// Mode, as defined in [FIPS‑197] and [NIST‑800‑38D]
+ /// </summary>
+ internal const string A128GCM = "A128GCM";
+
+ /// <summary>
+ /// Advanced Encryption Standard (AES) using 256 bit keys in Galois/Counter
+ /// Mode, as defined in [FIPS‑197] and [NIST‑800‑38D]
+ /// </summary>
+ internal const string A256GCM = "A256GCM";
+ }
+
+ /// <summary>
+ /// The set of enc (encryption method) header parameter values that are defined
+ /// by this specification for use with JWE. These algorithms are used to encrypt
+ /// the Plaintext, which produces the Ciphertext.
+ /// </summary>
+ /// <remarks>
+ /// http://self-issued.info/docs/draft-ietf-jose-json-web-algorithms-01.html#EncTable
+ /// </remarks>
+ internal static class JsonWebEncryptionMethods {
+ /// <summary>
+ /// Advanced Encryption Standard (AES) using 128 bit keys in Cipher Block Chaining mode, as defined in [FIPS‑197] and [NIST‑800‑38A]
+ /// </summary>
+ internal const string A128CBC = "A128CBC";
+
+ /// <summary>
+ /// Advanced Encryption Standard (AES) using 256 bit keys in Cipher Block Chaining mode, as defined in [FIPS‑197] and [NIST‑800‑38A]
+ /// </summary>
+ internal const string A256CBC = "A256CBC";
+
+ /// <summary>
+ /// Advanced Encryption Standard (AES) using 128 bit keys in Galois/Counter Mode, as defined in [FIPS‑197] and [NIST‑800‑38D]
+ /// </summary>
+ internal const string A128GCM = "A128GCM";
+
+ /// <summary>
+ /// Advanced Encryption Standard (AES) using 256 bit keys in Galois/Counter Mode, as defined in [FIPS‑197] and [NIST‑800‑38D]
+ /// </summary>
+ internal const string A256GCM = "A256GCM";
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2/OAuth2/Crypto/JweHeader.cs b/src/DotNetOpenAuth.OAuth2/OAuth2/Crypto/JweHeader.cs
new file mode 100644
index 0000000..2691da3
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2/OAuth2/Crypto/JweHeader.cs
@@ -0,0 +1,74 @@
+namespace DotNetOpenAuth.OAuth2.Crypto {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+
+ internal class JweHeader : JwtHeader {
+ private JweHeader() {
+ }
+
+ internal JweHeader(string algorithm, string encryptionMethod) {
+ Requires.NotNullOrEmpty(algorithm, "algorithm");
+ Requires.NotNullOrEmpty(encryptionMethod, "encryptionMethod");
+ this.Algorithm = algorithm;
+ this.EncryptionMethod = encryptionMethod;
+ }
+
+ /// <summary>
+ /// Gets or sets a value that identifies the cryptographic algorithm used to secure the JWS.
+ /// A list of defined alg values is presented in Section 3, Table 1 of the JSON Web Algorithms (JWA) [JWA]
+ /// specification. The processing of the alg header parameter requires that the value MUST be one that is
+ /// both supported and for which there exists a key for use with that algorithm associated with the party
+ /// that digitally signed or HMACed the content. The alg parameter value is case sensitive.
+ /// This header parameter is REQUIRED.
+ /// </summary>
+ [MessagePart("alg", IsRequired = true, AllowEmpty = false)]
+ internal string Algorithm { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value that identifies the symmetric encryption algorithm used to secure the Ciphertext.
+ /// A list of defined enc values is presented in Section 4, Table 3 of the JSON Web Algorithms (JWA) [JWA]
+ /// specification. The processing of the enc (encryption method) header parameter requires that the value
+ /// MUST be one that is supported. The enc value is case sensitive. This header parameter is REQUIRED.
+ /// </summary>
+ [MessagePart("enc", IsRequired = true, AllowEmpty = false)]
+ internal string EncryptionMethod { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value that identifies the cryptographic algorithm used to safeguard the integrity of the
+ /// Ciphertext and the parameters used to create it. The int parameter uses the same values as the JWS alg
+ /// parameter; a list of defined JWS alg values is presented in Section 3, Table 1 of the JSON Web Algorithms
+ /// (JWA) [JWA] specification. This header parameter is REQUIRED when an AEAD algorithm is not used to encrypt
+ /// the Plaintext and MUST NOT be present when an AEAD algorithm is used.
+ /// </summary>
+ [MessagePart("int")]
+ internal string IntegrityAlgorithm { get; set; }
+
+ /// <summary>
+ /// Gets or sets a hint indicating which specific key owned by the signer should be used to validate the digital signature.
+ /// This allows signers to explicitly signal a change of key to recipients. The interpretation of the contents of the kid
+ /// parameter is unspecified. This header parameter is OPTIONAL.
+ /// </summary>
+ [MessagePart("kid")]
+ internal string KeyIdentity { get; set; }
+
+ /// <summary>
+ /// Gets or sets the initialization Vector (iv) value for algorithms requiring it, represented as a base64url encoded string.
+ /// This header parameter is OPTIONAL.
+ /// </summary>
+ [MessagePart("iv", Encoder = typeof(Base64WebEncoder))]
+ internal byte[] IV { get; set; }
+
+ /// <summary>
+ /// Gets or sets the compression algorithm (zip) applied to the Plaintext before encryption, if any.
+ /// This specification defines the value GZIP to refer to the encoding format produced by the file
+ /// compression program "gzip" (GNU zip) as described in [RFC1952]; this format is a Lempel-Ziv coding
+ /// (LZ77) with a 32 bit CRC. If no zip parameter is present, or its value is none, no compression is
+ /// applied to the Plaintext before encryption. The zip value is case sensitive. This header parameter is OPTIONAL.
+ /// </summary>
+ [MessagePart("zip")]
+ internal string CompressionAlgorithm { get; set; }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2/OAuth2/Crypto/JweRsaEncryptionAlgorithm.cs b/src/DotNetOpenAuth.OAuth2/OAuth2/Crypto/JweRsaEncryptionAlgorithm.cs
new file mode 100644
index 0000000..0d2159d
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2/OAuth2/Crypto/JweRsaEncryptionAlgorithm.cs
@@ -0,0 +1,29 @@
+namespace DotNetOpenAuth.OAuth2.Crypto {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Security.Cryptography;
+ using System.Text;
+
+ internal class JweRsaEncryptionAlgorithm : JwtEncryptionAlgorithm {
+ private readonly RSACryptoServiceProvider recipientPublicKey;
+
+ private readonly bool useOaepPadding;
+
+ internal JweRsaEncryptionAlgorithm(RSACryptoServiceProvider recipientPublicKey, bool useOaepPadding = true)
+ : base(useOaepPadding ? JsonWebEncryptionAlgorithms.RSA_OAEP : JsonWebEncryptionAlgorithms.RSA1_5, JsonWebEncryptionMethods.A256CBC) {
+ Requires.NotNull(recipientPublicKey, "recipientPublicKey");
+ this.recipientPublicKey = recipientPublicKey;
+ this.useOaepPadding = useOaepPadding;
+ }
+
+ internal override void Encrypt(byte[] plainText, out byte[] cipherText, out byte[] integrityValue) {
+ cipherText = this.recipientPublicKey.Encrypt(plainText, this.useOaepPadding);
+ integrityValue = null; // RSA is an AEAD algorithm, so it doesn't need a separate integrity check.
+ }
+
+ internal override byte[] Decrypt(byte[] cipherText, byte[] integrityValue) {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2/OAuth2/Crypto/JwsHeader.cs b/src/DotNetOpenAuth.OAuth2/OAuth2/Crypto/JwsHeader.cs
new file mode 100644
index 0000000..7274de5
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2/OAuth2/Crypto/JwsHeader.cs
@@ -0,0 +1,36 @@
+namespace DotNetOpenAuth.OAuth2.Crypto {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+
+ internal class JwsHeader : JwtHeader {
+ private JwsHeader() {
+ }
+
+ internal JwsHeader(string algorithm) {
+ Requires.NotNullOrEmpty(algorithm, "algorithm");
+ this.Algorithm = algorithm;
+ }
+
+ /// <summary>
+ /// Gets or sets a value that identifies the cryptographic algorithm used to secure the JWS.
+ /// A list of defined alg values is presented in Section 3, Table 1 of the JSON Web Algorithms (JWA) [JWA]
+ /// specification. The processing of the alg header parameter requires that the value MUST be one that is
+ /// both supported and for which there exists a key for use with that algorithm associated with the party
+ /// that digitally signed or HMACed the content. The alg parameter value is case sensitive.
+ /// This header parameter is REQUIRED.
+ /// </summary>
+ [MessagePart("alg", IsRequired = true, AllowEmpty = false)]
+ internal string Algorithm { get; set; }
+
+ /// <summary>
+ /// Gets or sets a hint indicating which specific key owned by the signer should be used to validate the digital signature.
+ /// This allows signers to explicitly signal a change of key to recipients. The interpretation of the contents of the kid
+ /// parameter is unspecified. This header parameter is OPTIONAL.
+ /// </summary>
+ [MessagePart("kid")]
+ internal string KeyIdentity { get; set; }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2/OAuth2/Crypto/JwtEncryptionAlgorithm.cs b/src/DotNetOpenAuth.OAuth2/OAuth2/Crypto/JwtEncryptionAlgorithm.cs
new file mode 100644
index 0000000..b3ac78b
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2/OAuth2/Crypto/JwtEncryptionAlgorithm.cs
@@ -0,0 +1,41 @@
+//-----------------------------------------------------------------------
+// <copyright file="JwtEncryptionAlgorithm.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth2.Crypto {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+
+ internal abstract class JwtEncryptionAlgorithm : IDisposable {
+ protected JwtEncryptionAlgorithm(string algorithmName, string encryptionMethod) {
+ Requires.NotNullOrEmpty(algorithmName, "algorithmName");
+ Requires.NotNullOrEmpty(encryptionMethod, "encryptionMethod");
+ this.Header = new JweHeader(algorithmName, encryptionMethod);
+ }
+
+ internal JweHeader Header { get; private set; }
+
+ internal abstract void Encrypt(byte[] plainText, out byte[] cipherText, out byte[] integrityValue);
+
+ internal abstract byte[] Decrypt(byte[] cipherText, byte[] integrityValue);
+
+ public void Dispose() {
+ this.Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool disposing) {
+ }
+
+ protected void KeyDerivation(byte[] contentMasterKey, out byte[] contentEncryptionKey, out byte[] contentIntegrityKey) {
+ // Implementing this would be manual, or involve P/Invoke I think.
+ // http://msdn.microsoft.com/en-us/library/windows/desktop/aa375393(v=vs.85).aspx
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2/OAuth2/Crypto/JwtHeader.cs b/src/DotNetOpenAuth.OAuth2/OAuth2/Crypto/JwtHeader.cs
new file mode 100644
index 0000000..1553946
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2/OAuth2/Crypto/JwtHeader.cs
@@ -0,0 +1,16 @@
+namespace DotNetOpenAuth.OAuth2.Crypto {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+
+ internal class JwtHeader : JwtMessageBase {
+ internal JwtHeader() {
+ this.Type = "JWT";
+ }
+
+ [MessagePart("typ")]
+ internal string Type { get; set; }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2/OAuth2/Crypto/JwtHmacShaSigningAlgorithm.cs b/src/DotNetOpenAuth.OAuth2/OAuth2/Crypto/JwtHmacShaSigningAlgorithm.cs
new file mode 100644
index 0000000..80d836c
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2/OAuth2/Crypto/JwtHmacShaSigningAlgorithm.cs
@@ -0,0 +1,84 @@
+//-----------------------------------------------------------------------
+// <copyright file="JwtHmacShaSigningAlgorithm.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth2.Crypto {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Security.Cryptography;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+
+ internal class JwtHmacShaSigningAlgorithm : JwtSigningAlgorithm {
+ private readonly HashAlgorithm algorithm;
+
+ internal enum Algorithm {
+ HmacSha256,
+ HmacSha384,
+ HmacSha512,
+ }
+
+ private JwtHmacShaSigningAlgorithm(string algorithmName, HMAC algorithm)
+ : base(algorithmName) {
+ Requires.NotNull(algorithm, "algorithm");
+ this.algorithm = algorithm;
+ }
+
+ internal static JwtSigningAlgorithm Create(Algorithm algorithm, string keyHandle, byte[] key) {
+ Requires.NotNull(key, "key");
+
+ string webAlgorithmName, cryptoName;
+ switch (algorithm) {
+ case Algorithm.HmacSha256:
+ cryptoName = "HMAC-SHA256";
+ webAlgorithmName = JsonWebSignatureAlgorithms.HmacSha256;
+ break;
+ case Algorithm.HmacSha384:
+ cryptoName = "HMAC-SHA384";
+ webAlgorithmName = JsonWebSignatureAlgorithms.HmacSha384;
+ break;
+ case Algorithm.HmacSha512:
+ cryptoName = "HMAC-SHA512";
+ webAlgorithmName = JsonWebSignatureAlgorithms.HmacSha512;
+ break;
+ default:
+ Requires.InRange(false, "algorithm");
+ throw Assumes.NotReachable();
+ }
+
+ HMAC hmac = null;
+ try {
+ hmac = HMAC.Create(cryptoName);
+ hmac.Key = key;
+ var result = new JwtHmacShaSigningAlgorithm(webAlgorithmName, hmac);
+ result.Header.KeyIdentity = keyHandle;
+ return result;
+ } catch {
+ if (hmac != null) {
+ hmac.Dispose();
+ }
+
+ throw;
+ }
+ }
+
+ internal override byte[] Sign(byte[] securedInput) {
+ return algorithm.ComputeHash(securedInput);
+ }
+
+ internal override bool Verify(byte[] securedInput, byte[] signature) {
+ return MessagingUtilities.AreEquivalentConstantTime(this.Sign(securedInput), signature);
+ }
+
+ protected override void Dispose(bool disposing) {
+ if (disposing) {
+ this.algorithm.Dispose();
+ }
+
+ base.Dispose();
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2/OAuth2/Crypto/JwtMessageBase.cs b/src/DotNetOpenAuth.OAuth2/OAuth2/Crypto/JwtMessageBase.cs
new file mode 100644
index 0000000..04b9655
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2/OAuth2/Crypto/JwtMessageBase.cs
@@ -0,0 +1,26 @@
+namespace DotNetOpenAuth.OAuth2.Crypto {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+
+ internal class JwtMessageBase : IMessage {
+ private static readonly Version version = new Version(1, 0);
+
+ private readonly Dictionary<string, string> extraData = new Dictionary<string, string>();
+
+ public Version Version {
+ get { return version; }
+ }
+
+ public IDictionary<string, string> ExtraData {
+ get { return this.extraData; }
+ }
+
+ public virtual void EnsureValidMessage() {
+ // The JWT spec mandates that any unexpected data in the JWT header or claims set cause a rejection.
+ ErrorUtilities.VerifyProtocol(this.ExtraData.Count == 0, "Unrecognized data in JWT access token with key '{0}'. Token rejected.", this.ExtraData.First().Key);
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2/OAuth2/Crypto/JwtRsaShaSigningAlgorithm.cs b/src/DotNetOpenAuth.OAuth2/OAuth2/Crypto/JwtRsaShaSigningAlgorithm.cs
new file mode 100644
index 0000000..48c1b60
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2/OAuth2/Crypto/JwtRsaShaSigningAlgorithm.cs
@@ -0,0 +1,82 @@
+//-----------------------------------------------------------------------
+// <copyright file="JwtRsaShaSigningAlgorithm.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth2.Crypto {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Security.Cryptography;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+
+ internal class JwtRsaShaSigningAlgorithm : JwtSigningAlgorithm {
+ private readonly RSACryptoServiceProvider algorithm;
+
+ private readonly HashAlgorithm hashAlgorithm;
+
+ internal enum HashSize {
+ Sha256,
+ Sha384,
+ Sha512,
+ }
+
+ internal JwtRsaShaSigningAlgorithm(string algorithmName, RSACryptoServiceProvider algorithm, HashAlgorithm hashAlgorithm)
+ : base(algorithmName) {
+ Requires.NotNull(algorithm, "algorithm");
+ Requires.NotNull(hashAlgorithm, "hashAlgorithm");
+ this.algorithm = algorithm;
+ this.hashAlgorithm = hashAlgorithm;
+ }
+
+ internal static JwtRsaShaSigningAlgorithm Create(RSACryptoServiceProvider algorithm, HashSize hashSize) {
+ Requires.NotNull(algorithm, "algorithm");
+
+ string webAlgorithmName, cryptoName;
+ switch (hashSize) {
+ case HashSize.Sha256:
+ webAlgorithmName = JsonWebSignatureAlgorithms.RsaSha256;
+ cryptoName = "SHA256";
+ break;
+ case HashSize.Sha384:
+ webAlgorithmName = JsonWebSignatureAlgorithms.RsaSha384;
+ cryptoName = "SHA384";
+ break;
+ case HashSize.Sha512:
+ webAlgorithmName = JsonWebSignatureAlgorithms.RsaSha512;
+ cryptoName = "SHA512";
+ break;
+ default:
+ Requires.InRange(false, "algorithm");
+ throw Assumes.NotReachable();
+ }
+
+ HashAlgorithm hashAlgorithm = HashAlgorithm.Create(cryptoName);
+ try {
+ return new JwtRsaShaSigningAlgorithm(webAlgorithmName, algorithm, hashAlgorithm);
+ } catch {
+ hashAlgorithm.Dispose();
+ throw;
+ }
+ }
+
+ internal override byte[] Sign(byte[] securedInput) {
+ return algorithm.SignData(securedInput, this.hashAlgorithm);
+ }
+
+ internal override bool Verify(byte[] securedInput, byte[] signature) {
+ return algorithm.VerifyData(securedInput, this.hashAlgorithm, signature);
+ }
+
+ protected override void Dispose(bool disposing) {
+ if (disposing) {
+ // We only own the hash algorithm -- not the RSA algorithm.
+ this.hashAlgorithm.Dispose();
+ }
+
+ base.Dispose();
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2/OAuth2/Crypto/JwtSigningAlgorithm.cs b/src/DotNetOpenAuth.OAuth2/OAuth2/Crypto/JwtSigningAlgorithm.cs
new file mode 100644
index 0000000..116c1ca
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2/OAuth2/Crypto/JwtSigningAlgorithm.cs
@@ -0,0 +1,33 @@
+//-----------------------------------------------------------------------
+// <copyright file="JwtSigningAlgorithm.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth2.Crypto {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+
+ internal abstract class JwtSigningAlgorithm : IDisposable {
+ protected JwtSigningAlgorithm(string algorithmName) {
+ Requires.NotNullOrEmpty(algorithmName, "algorithmName");
+ this.Header = new JwsHeader(algorithmName);
+ }
+
+ internal JwsHeader Header { get; private set; }
+
+ internal abstract byte[] Sign(byte[] securedInput);
+
+ internal abstract bool Verify(byte[] securedInput, byte[] signature);
+
+ public void Dispose() {
+ this.Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool disposing) {
+ }
+ }
+}