![]() |
VOOZH | about |
dotnet add package AWSSignatureGenerator --version 1.1.0
NuGet\Install-Package AWSSignatureGenerator -Version 1.1.0
<PackageReference Include="AWSSignatureGenerator" Version="1.1.0" />
<PackageVersion Include="AWSSignatureGenerator" Version="1.1.0" />Directory.Packages.props
<PackageReference Include="AWSSignatureGenerator" />Project file
paket add AWSSignatureGenerator --version 1.1.0
#r "nuget: AWSSignatureGenerator, 1.1.0"
#:package AWSSignatureGenerator@1.1.0
#addin nuget:?package=AWSSignatureGenerator&version=1.1.0Install as a Cake Addin
#tool nuget:?package=AWSSignatureGenerator&version=1.1.0Install as a Cake Tool
A .NET class library for generating and validating AWS V4 signatures and legacy Amazon S3 V2 signatures, including streaming (chunked) V4 signatures used by AWSSDK 4.x. Built using the AWS CLI and boto as a reference implementation.
Encounter an issue or have an enhancement request? Please file an issue or start a discussion here!
V2SignatureResultV2SignedUrlResultV4ChunkSigner for validating aws-chunked upload payloadsAwsChunkedStreamReader for parsing aws-chunked encoded streamsSigningKeyBytes property for accessing raw signing key bytessignedHeaders parameter to restrict canonical request to specified headersauthorization, amz-sdk-invocation-id, amz-sdk-request, and other non-signable headersUse V4SignatureResult to generate a standard V4 signature for any AWS request. This is the most common use case — signing or validating a request where the entire payload is available upfront.
using AWSSignatureGenerator;
NameValueCollection headers = new NameValueCollection
{
{ "Host", "examplebucket.s3.amazonaws.com" },
{ "x-amz-content-sha256", "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" },
{ "x-amz-date", "20231109T012345Z" }
};
V4SignatureResult result = new V4SignatureResult(
"20231109T012345Z", // timestamp, of the form yyyyMMddTHHmmssZ
"GET", // HTTP method
"https://examplebucket.s3.amazonaws.com/test.txt",
"AKIAIOSFODNN7EXAMPLE", // access key
"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", // secret key
"us-east-1", // region
"s3", // service
headers, // request headers (must include "host")
null, // request body: string, byte[], or Stream
V4PayloadHashEnum.Signed // payload hashing mode
);
Console.WriteLine("Signature : " + result.Signature);
Console.WriteLine("Authorization header : " + result.AuthorizationHeader);
| Mode | When to Use |
|---|---|
Signed |
Default. Computes SHA-256 of the request body. Use for standard requests where the full payload is available. |
Unsigned |
Payload hash is the literal UNSIGNED-PAYLOAD. Use when the server does not require payload signing (e.g. presigned URLs). |
IsStreaming |
Payload hash is the literal STREAMING-UNSIGNED-PAYLOAD-TRAILER. Use for unsigned streaming uploads. |
StreamingSigned |
Payload hash is the literal STREAMING-AWS4-HMAC-SHA256-PAYLOAD. Use for AWSSDK 4.x chunked uploads without trailing checksums. |
StreamingSignedTrailer |
Payload hash is the literal STREAMING-AWS4-HMAC-SHA256-PAYLOAD-TRAILER. Use for AWSSDK 4.x chunked uploads with trailing checksums (e.g. CRC32). |
The requestBody parameter accepts string, byte[], or Stream. When using Signed mode, the body is hashed to produce the payload hash. For all other modes, the body parameter is ignored (pass null).
// String body
V4SignatureResult result = new V4SignatureResult(timestamp, "PUT", url, accessKey, secretKey,
region, "s3", headers, "Hello World", V4PayloadHashEnum.Signed);
// Byte array body
byte[] body = Encoding.UTF8.GetBytes("Hello World");
V4SignatureResult result = new V4SignatureResult(timestamp, "PUT", url, accessKey, secretKey,
region, "s3", headers, body, V4PayloadHashEnum.Signed);
// Stream body (position is reset after hashing)
using FileStream fs = File.OpenRead("largefile.bin");
V4SignatureResult result = new V4SignatureResult(timestamp, "PUT", url, accessKey, secretKey,
region, "s3", headers, fs, V4PayloadHashEnum.Signed);
Use V2SignatureResult when you specifically need Amazon S3 Signature Version 2 header authentication. SigV2 is deprecated for AWS S3 and is not supported in many modern AWS S3 scenarios. Prefer V4 unless you are maintaining legacy S3 workflows or interoperating with an S3-compatible service that requires V2.
using AWSSignatureGenerator;
NameValueCollection headers = new NameValueCollection
{
{ "Date", "Tue, 27 Mar 2007 19:36:42 +0000" }
};
using V2SignatureResult result = new V2SignatureResult(
"GET",
"https://examplebucket.s3.amazonaws.com/photos/puppy.jpg",
"AKIDEXAMPLE",
"wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY",
headers);
Console.WriteLine("Signature : " + result.Signature);
Console.WriteLine("Authorization header : " + result.AuthorizationHeader);
Important V2 fields exposed by the result include ContentMd5, ContentType, DateElement, CanonicalizedAmzHeaders, CanonicalizedResource, StringToSign, Signature, and AuthorizationHeader.
Use V2SignedUrlResult to generate a legacy S3 SigV2 signed URL. The expiration is expressed as Unix epoch seconds, matching the S3 V2 query-string authentication format.
using AWSSignatureGenerator;
using V2SignedUrlResult result = new V2SignedUrlResult(
"GET",
"https://examplebucket.s3.amazonaws.com/photos/puppy.jpg",
"AKIDEXAMPLE",
"wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY",
1175139620);
Console.WriteLine("Signed URL : " + result.SignedUrl);
The signed URL includes AWSAccessKeyId, Expires, and Signature. The raw Base64 signature is available through Signature, and the RFC 3986 encoded value is available through EncodedSignature.
AWSSDK 4.x for .NET sends PUT/POST requests with body content using streaming (chunked) signatures rather than standard V4 signatures. The library provides full support for validating these requests.
A streaming signature request has three layers of validation:
X-Amz-Trailer is present)The seed signature is a standard V4 signature where the payload hash is a literal string (not the hash of the body). Detect the mode from the x-amz-content-sha256 header:
// Detect streaming mode from the x-amz-content-sha256 header
string contentSha256 = request.Headers["x-amz-content-sha256"];
V4PayloadHashEnum hashMode = contentSha256 switch
{
"STREAMING-AWS4-HMAC-SHA256-PAYLOAD-TRAILER" => V4PayloadHashEnum.StreamingSignedTrailer,
"STREAMING-AWS4-HMAC-SHA256-PAYLOAD" => V4PayloadHashEnum.StreamingSigned,
"UNSIGNED-PAYLOAD" => V4PayloadHashEnum.Unsigned,
_ => V4PayloadHashEnum.Signed
};
V4SignatureResult seedResult = new V4SignatureResult(
timestamp, method, url, accessKey, secretKey, region, "s3",
headers, null, hashMode); // null body — not hashed for streaming
// Compare against the Signature field in the Authorization header
if (!seedResult.Signature.Equals(requestSignature))
throw new Exception("Seed signature does not match");
Use V4ChunkSigner to validate each chunk as it arrives. The signer chains signatures — each chunk's signature depends on the previous one.
using V4ChunkSigner signer = new V4ChunkSigner(
timestamp, // same timestamp as the request
region, // e.g. "us-east-1"
"s3", // service
seedResult.SigningKeyBytes, // raw signing key bytes
seedResult.Signature); // seed signature
// For each chunk read from the stream:
while (true)
{
// Read the next chunk (your code to parse the wire format)
(byte[] data, string sig, bool isFinal) = ReadNextChunk(stream);
if (!signer.ValidateChunk(data, sig))
throw new Exception("Chunk signature does not match");
if (isFinal) break;
}
When the request includes X-Amz-Trailer, trailing headers (e.g. x-amz-checksum-crc32) are sent after the final chunk, followed by a trailer signature.
// After validating all chunks including the final zero-length chunk:
SortedDictionary<string, string> trailerHeaders = new SortedDictionary<string, string>
{
{ "x-amz-checksum-crc32", checksumValue }
};
if (!signer.ValidateTrailer(trailerHeaders, trailerSignature))
throw new Exception("Trailer signature does not match");
Use AwsChunkedStreamReader to parse the aws-chunked wire format. This handles the chunk framing so you don't have to.
using AwsChunkedStreamReader reader = new AwsChunkedStreamReader(requestBodyStream);
using V4ChunkSigner signer = new V4ChunkSigner(
timestamp, region, "s3", seedResult.SigningKeyBytes, seedResult.Signature);
while (true)
{
AwsChunkResult chunk = await reader.ReadNextChunkAsync();
if (chunk == null) break;
if (chunk.Signature != null)
{
if (!signer.ValidateChunk(chunk.Data, chunk.Signature))
throw new Exception("Chunk signature mismatch");
}
if (chunk.IsFinal)
{
// Check for trailing headers
AwsChunkResult trailer = await reader.ReadNextChunkAsync();
if (trailer?.TrailerHeaders != null && trailer.TrailerSignature != null)
{
if (!signer.ValidateTrailer(trailer.TrailerHeaders, trailer.TrailerSignature))
throw new Exception("Trailer signature mismatch");
}
break;
}
// Process chunk.Data (write to file, etc.)
}
AWSSDK 4.x sends chunked uploads in this format:
<hex-chunk-size>;chunk-signature=<signature>\r\n
<chunk-data>\r\n
...
0;chunk-signature=<final-signature>\r\n
\r\n
x-amz-checksum-crc32:<base64-value>\r\n (if trailers present)
\r\n
0;chunk-signature=<trailer-signature>\r\n (if trailers present)
\r\n
When validating signatures on the server side, the server receives ALL request headers but should only include the headers listed in the SignedHeaders field of the Authorization header. Use the signedHeaders constructor overload:
// Parse SignedHeaders from the Authorization header
// Authorization: AWS4-HMAC-SHA256 Credential=.../aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=...
List<string> signedHeaders = ParseSignedHeaders(authorizationHeader);
// e.g. ["host", "x-amz-content-sha256", "x-amz-date"]
V4SignatureResult result = new V4SignatureResult(
timestamp, method, url, accessKey, secretKey, region, "s3",
allRequestHeaders, // pass ALL headers from the request
signedHeaders, // only these will be included in the canonical request
requestBody,
payloadHashMode);
if (!result.Signature.Equals(providedSignature))
throw new Exception("Signature mismatch");
Without the signedHeaders parameter, the library uses a default ignore list to filter headers. This works for client-side signature generation but may include extra headers during server-side validation (since servers see headers the client did not sign). The signedHeaders parameter ensures exact parity with the client's canonical request.
The main class for generating standard and seed signatures.
| Property | Type | Description |
|---|---|---|
Signature |
string |
Final V4 signature as lowercase hex |
AuthorizationHeader |
string |
Complete Authorization header value |
SigningKeyBytes |
byte[] |
Raw signing key bytes (needed by V4ChunkSigner) |
SigningKey |
string |
Signing key as lowercase hex |
HashedPayload |
string |
Payload hash (computed or literal, depending on mode) |
CanonicalRequest |
string |
Full canonical request string |
StringToSign |
string |
String to sign |
SignedHeaders |
List<string> |
Sorted list of signed header names |
Computes and validates streaming chunk and trailer signatures.
| Method | Returns | Description |
|---|---|---|
ComputeChunkSignature(byte[] chunkData) |
string |
Compute expected signature for the next chunk |
ValidateChunk(byte[] chunkData, string providedSignature) |
bool |
Validate a chunk's signature |
ComputeTrailerSignature(SortedDictionary<string, string> trailerHeaders) |
string |
Compute expected trailer signature |
ValidateTrailer(SortedDictionary<string, string> trailerHeaders, string providedSignature) |
bool |
Validate the trailer signature |
Generates legacy Amazon S3 Signature Version 2 Authorization header signatures.
| Property | Type | Description |
|---|---|---|
Signature |
string |
Final V2 signature as Base64 HMAC-SHA1 |
AuthorizationHeader |
string |
Complete Authorization header value |
ContentMd5 |
string |
Content-MD5 value included in the string to sign |
ContentType |
string |
Content-Type value included in the string to sign |
DateElement |
string |
Date value included in the string to sign, or empty when x-amz-date is signed |
CanonicalizedAmzHeaders |
string |
Canonicalized x-amz-* headers |
CanonicalizedResource |
string |
S3 canonical resource |
StringToSign |
string |
Full S3 V2 string to sign |
Generates legacy Amazon S3 Signature Version 2 signed URLs.
| Property | Type | Description |
|---|---|---|
SignedUrl |
string |
URL containing AWSAccessKeyId, Expires, and Signature |
Signature |
string |
Raw Base64 HMAC-SHA1 signature |
EncodedSignature |
string |
RFC 3986 encoded signature query value |
Expires |
long |
Expiration time as Unix epoch seconds |
ExpiresAt |
DateTimeOffset |
Expiration time as a UTC date/time |
CanonicalizedAmzHeaders |
string |
Canonicalized x-amz-* headers that signed URL consumers must send |
CanonicalizedResource |
string |
S3 canonical resource |
StringToSign |
string |
Full S3 V2 string to sign |
Reads aws-chunked encoded streams and yields AwsChunkResult objects.
| Method | Returns | Description |
|---|---|---|
ReadNextChunkAsync(CancellationToken token) |
Task<AwsChunkResult> |
Read the next chunk from the stream |
| Property | Type | Description |
|---|---|---|
Data |
byte[] |
Chunk data (empty for final chunk) |
Signature |
string |
Chunk signature |
IsFinal |
bool |
True if this is the final zero-length chunk |
TrailerHeaders |
SortedDictionary<string, string> |
Trailing headers (if present) |
TrailerSignature |
string |
Trailer signature (if present) |
Refer to CHANGELOG.md for details.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 net5.0 was computed. net5.0-windows net5.0-windows was computed. net6.0 net6.0 was computed. net6.0-android net6.0-android was computed. net6.0-ios net6.0-ios was computed. net6.0-maccatalyst net6.0-maccatalyst was computed. net6.0-macos net6.0-macos was computed. net6.0-tvos net6.0-tvos was computed. net6.0-windows net6.0-windows was computed. net7.0 net7.0 was computed. net7.0-android net7.0-android was computed. net7.0-ios net7.0-ios was computed. net7.0-maccatalyst net7.0-maccatalyst was computed. net7.0-macos net7.0-macos was computed. net7.0-tvos net7.0-tvos was computed. net7.0-windows net7.0-windows was computed. net8.0 net8.0 is compatible. net8.0-android net8.0-android was computed. net8.0-browser net8.0-browser was computed. net8.0-ios net8.0-ios was computed. net8.0-maccatalyst net8.0-maccatalyst was computed. net8.0-macos net8.0-macos was computed. net8.0-tvos net8.0-tvos was computed. net8.0-windows net8.0-windows was computed. net9.0 net9.0 was computed. net9.0-android net9.0-android was computed. net9.0-browser net9.0-browser was computed. net9.0-ios net9.0-ios was computed. net9.0-maccatalyst net9.0-maccatalyst was computed. net9.0-macos net9.0-macos was computed. net9.0-tvos net9.0-tvos was computed. net9.0-windows net9.0-windows was computed. net10.0 net10.0 is compatible. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 netcoreapp2.0 was computed. netcoreapp2.1 netcoreapp2.1 was computed. netcoreapp2.2 netcoreapp2.2 was computed. netcoreapp3.0 netcoreapp3.0 was computed. netcoreapp3.1 netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 netstandard2.0 is compatible. netstandard2.1 netstandard2.1 is compatible. |
| .NET Framework | net461 net461 was computed. net462 net462 was computed. net463 net463 was computed. net47 net47 was computed. net471 net471 was computed. net472 net472 was computed. net48 net48 was computed. net481 net481 was computed. |
| MonoAndroid | monoandroid monoandroid was computed. |
| MonoMac | monomac monomac was computed. |
| MonoTouch | monotouch monotouch was computed. |
| Tizen | tizen40 tizen40 was computed. tizen60 tizen60 was computed. |
| Xamarin.iOS | xamarinios xamarinios was computed. |
| Xamarin.Mac | xamarinmac xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos xamarinwatchos was computed. |
Showing the top 3 NuGet packages that depend on AWSSignatureGenerator:
| Package | Downloads |
|---|---|
|
S3Server
Emulated Amazon Web Services (AWS) Simple Storage Service (S3) server-side interface. |
|
|
S3Lite
Lightweight Amazon S3 client without the heft and dependency drag of the official library. |
|
|
EASYTools.S3Server
Emulated Amazon Web Services (AWS) Simple Storage Service (S3) server-side interface. |
This package is not used by any popular GitHub repositories.
Additive legacy Amazon S3 Signature Version 2 header signing and signed URL support. AWS V4 behavior is unchanged.