Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DetachedSignatureFactory accepts pre-hashed content as payload #53

Merged
merged 9 commits into from
Oct 25, 2023
21 changes: 16 additions & 5 deletions CoseSign1/DetachedSignatureFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ public CoseSign1Message CreateDetachedSignature(
/// <param name="contentType">A media type string following https://datatracker.ietf.org/doc/html/rfc6838.</param>
/// <returns>A CoseSign1Message which can be used as a detached signature validation of the payload.</returns>
/// <exception cref="ArgumentNullException">The contentType parameter was empty or null</exception>
/// <exception cref="ArgumentException">Hash size does not correspond to any known hash algorithms</exception>
public CoseSign1Message CreateDetachedSignatureFromHash(
ReadOnlyMemory<byte> rawHash,
ICoseSigningKeyProvider signingKeyProvider,
Expand Down Expand Up @@ -121,6 +122,7 @@ public Task<CoseSign1Message> CreateDetachedSignatureAsync(
/// <param name="contentType">A media type string following https://datatracker.ietf.org/doc/html/rfc6838.</param>
/// <returns>A CoseSign1Message which can be used as a detached signature validation of the payload.</returns>
/// <exception cref="ArgumentNullException">The contentType parameter was empty or null</exception>
/// <exception cref="ArgumentException">Hash size does not correspond to any known hash algorithms</exception>
public Task<CoseSign1Message> CreateDetachedSignatureFromHashAsync(
ReadOnlyMemory<byte> rawHash,
ICoseSigningKeyProvider signingKeyProvider,
Expand Down Expand Up @@ -157,6 +159,7 @@ public CoseSign1Message CreateDetachedSignature(
/// <param name="contentType">A media type string following https://datatracker.ietf.org/doc/html/rfc6838.</param>
/// <returns>A CoseSign1Message which can be used as a detached signature validation of the payload.</returns>
/// <exception cref="ArgumentNullException">The contentType parameter was empty or null</exception>
/// <exception cref="ArgumentException">Hash size does not correspond to any known hash algorithms</exception>
public CoseSign1Message CreateDetachedSignatureFromHash(
Stream rawHash,
ICoseSigningKeyProvider signingKeyProvider,
Expand Down Expand Up @@ -193,6 +196,7 @@ public Task<CoseSign1Message> CreateDetachedSignatureAsync(
/// <param name="contentType">A media type string following https://datatracker.ietf.org/doc/html/rfc6838.</param>
/// <returns>A CoseSign1Message which can be used as a detached signature validation of the payload.</returns>
/// <exception cref="ArgumentNullException">The contentType parameter was empty or null</exception>
/// <exception cref="ArgumentException">Hash size does not correspond to any known hash algorithms</exception>
public Task<CoseSign1Message> CreateDetachedSignatureFromHashAsync(
Stream rawHash,
ICoseSigningKeyProvider signingKeyProvider,
Expand Down Expand Up @@ -229,6 +233,7 @@ public ReadOnlyMemory<byte> CreateDetachedSignatureBytes(
/// <param name="contentType">A media type string following https://datatracker.ietf.org/doc/html/rfc6838.</param>
/// <returns>A byte[] representation of a CoseSign1Message which can be used as a detached signature validation of the payload.</returns>
/// <exception cref="ArgumentNullException">The contentType parameter was empty or null</exception>
/// <exception cref="ArgumentException">Hash size does not correspond to any known hash algorithms</exception>
public ReadOnlyMemory<byte> CreateDetachedSignatureBytesFromHash(
ReadOnlyMemory<byte> rawHash,
ICoseSigningKeyProvider signingKeyProvider,
Expand Down Expand Up @@ -265,6 +270,7 @@ public Task<ReadOnlyMemory<byte>> CreateDetachedSignatureBytesAsync(
/// <param name="contentType">A media type string following https://datatracker.ietf.org/doc/html/rfc6838.</param>
/// <returns>A Task which when completed returns a byte[] representation of a CoseSign1Message which can be used as a detached signature validation of the payload.</returns>
/// <exception cref="ArgumentNullException">The contentType parameter was empty or null</exception>
/// <exception cref="ArgumentException">Hash size does not correspond to any known hash algorithms</exception>
public Task<ReadOnlyMemory<byte>> CreateDetachedSignatureBytesFromHashAsync(
ReadOnlyMemory<byte> rawHash,
ICoseSigningKeyProvider signingKeyProvider,
Expand Down Expand Up @@ -301,6 +307,7 @@ public ReadOnlyMemory<byte> CreateDetachedSignatureBytes(
/// <param name="contentType">A media type string following https://datatracker.ietf.org/doc/html/rfc6838.</param>
/// <returns>A byte[] representation of a CoseSign1Message which can be used as a detached signature validation of the payload.</returns>
/// <exception cref="ArgumentNullException">The contentType parameter was empty or null</exception>
/// <exception cref="ArgumentException">Hash size does not correspond to any known hash algorithms</exception>
public ReadOnlyMemory<byte> CreateDetachedSignatureBytesFromHash(
Stream rawHash,
ICoseSigningKeyProvider signingKeyProvider,
Expand Down Expand Up @@ -337,6 +344,7 @@ public Task<ReadOnlyMemory<byte>> CreateDetachedSignatureBytesAsync(
/// <param name="contentType">A media type string following https://datatracker.ietf.org/doc/html/rfc6838.</param>
/// <returns>A Task which when completed returns a byte[] representation of a CoseSign1Message which can be used as a detached signature validation of the payload.</returns>
/// <exception cref="ArgumentNullException">The contentType parameter was empty or null</exception>
elantiguamsft marked this conversation as resolved.
Show resolved Hide resolved
/// <exception cref="ArgumentException">Hash size does not correspond to any known hash algorithms</exception>
public Task<ReadOnlyMemory<byte>> CreateDetachedSignatureBytesFromHashAsync(
Stream rawHash,
ICoseSigningKeyProvider signingKeyProvider,
Expand All @@ -356,8 +364,10 @@ public Task<ReadOnlyMemory<byte>> CreateDetachedSignatureBytesFromHashAsync(
/// <param name="contentType">The user specified content type.</param>
/// <param name="streamPayload">If not null, then Stream API's on the CoseSign1MessageFactory are used.</param>
/// <param name="bytePayload">If streamPayload is null then this must be specified and must not be null and will use the Byte API's on the CoseSign1MesssageFactory</param>
/// <param name="payloadHashed">True if the payload represents the raw hash</param>
/// <returns>Either a CoseSign1Message or a ReadOnlyMemory{byte} representing the CoseSign1Message object.</returns>
/// <exception cref="ArgumentNullException">The contentType parameter was empty or null</exception>
/// <exception cref="ArgumentException">payloadHashed is set, but hash size does not correspond to any known hash algorithms</exception>
private object CreateDetachedSignatureWithChecksInternal(
bool returnBytes,
ICoseSigningKeyProvider signingKeyProvider,
Expand Down Expand Up @@ -392,7 +402,7 @@ private object CreateDetachedSignatureWithChecksInternal(
: bytePayload!.Value.ToArray();
try
{
HashAlgorithmName algoName = SizeToAlgorithm[hash.Length];
HashAlgorithmName algoName = SizeInBytesToAlgorithm[hash.Length];
extendedContentType = ExtendContentType(contentType, algoName);
}
catch (KeyNotFoundException e)
Expand All @@ -416,9 +426,9 @@ private object CreateDetachedSignatureWithChecksInternal(
}

/// <summary>
/// quick lookup of algorithm name based on hash size
/// quick lookup of algorithm name based on size of raw hash in bytes
elantiguamsft marked this conversation as resolved.
Show resolved Hide resolved
/// </summary>
private static readonly ConcurrentDictionary<int, HashAlgorithmName> SizeToAlgorithm = new(
private static readonly ConcurrentDictionary<int, HashAlgorithmName> SizeInBytesToAlgorithm = new(
new Dictionary<int, HashAlgorithmName>()
{
{ 16, HashAlgorithmName.MD5 },
Expand Down Expand Up @@ -451,8 +461,9 @@ private object CreateDetachedSignatureWithChecksInternal(
/// Method which produces a mime type extension based on the given content type and hash algorithm name.
/// </summary>
/// <param name="contentType">The content type to append the hash value to if not already appended.</param>
/// <returns></returns>
elantiguamsft marked this conversation as resolved.
Show resolved Hide resolved
private string ExtendContentType(string contentType, HashAlgorithmName algorithmName)
/// <param name="algorithmName">The "HashAlgorithmName" to append if not already appended.</param>
/// <returns>A string representing the content type with an appended hash algorithm</returns>
private static string ExtendContentType(string contentType, HashAlgorithmName algorithmName)
{
// extract from the string cache to keep string allocations down.
string extensionMapping = MimeExtensionMap.GetOrAdd(algorithmName.Name, (name) => $"+hash-{name.ToLowerInvariant()}");
Expand Down
Loading