/// <summary> /// Computes the derived signature for a chunk of data of given length in the input buffer, /// placing a formatted chunk with headers, signature and data into the output buffer /// ready for streaming back to the consumer. /// </summary> /// <param name="dataLen"></param> private void ConstructOutputBufferChunk(int dataLen) { // if the input wasn't sufficient to fill the buffer, size it // down to make the subseqent hashing/computations easier since // they don't take any length arguments if (dataLen > 0 && dataLen < _inputBuffer.Length) { var temp = new byte[dataLen]; Buffer.BlockCopy(_inputBuffer, 0, temp, 0, dataLen); _inputBuffer = temp; } var chunkHeader = new StringBuilder(); // variable-length size of the embedded chunk data in hex chunkHeader.Append(dataLen.ToString("X", CultureInfo.InvariantCulture)); const string nonsigExtension = ""; // signature-extension var chunkStringToSign = CHUNK_STRING_TO_SIGN_PREFIX + "\n" + HeaderSigningResult.ISO8601DateTime + "\n" + HeaderSigningResult.Scope + "\n" + PreviousChunkSignature + "\n" + AWSSDKUtils.ToHex(AWS4Signer.ComputeHash(nonsigExtension), true) + "\n" + (dataLen > 0 ? AWSSDKUtils.ToHex(AWS4Signer.ComputeHash(_inputBuffer), true) : AWS4Signer.EmptyBodySha256); var chunkSignature = AWSSDKUtils.ToHex(AWS4Signer.SignBlob(HeaderSigningResult.SigningKey, chunkStringToSign), true); PreviousChunkSignature = chunkSignature; chunkHeader.Append(nonsigExtension + CHUNK_SIGNATURE_HEADER + chunkSignature); chunkHeader.Append(CLRF); try { var header = Encoding.UTF8.GetBytes(chunkHeader.ToString()); var trailer = Encoding.UTF8.GetBytes(CLRF); var writePos = 0; Buffer.BlockCopy(header, 0, _outputBuffer, writePos, header.Length); writePos += header.Length; if (dataLen > 0) { Buffer.BlockCopy(_inputBuffer, 0, _outputBuffer, writePos, dataLen); writePos += dataLen; } Buffer.BlockCopy(trailer, 0, _outputBuffer, writePos, trailer.Length); _outputBufferPos = 0; _outputBufferDataLen = header.Length + dataLen + trailer.Length; } catch (Exception e) { throw new AmazonClientException("Unable to sign the chunked data. " + e.Message, e); } }
/// <summary> /// Constructs the signed trailing headers, optionally including /// the selected checksum for this stream's data. For example: /// trailing-header-A:value CRLF /// trailing-header-B:value CRLF /// x-amz-trailer-signature:signature_value CRLF /// CRLF /// </summary> /// <returns>Stream chunk containing the trailing headers and their signature</returns> private string ConstructSignedTrailersChunk() { // If the trailing headers included a trailing checksum, set the hash value if (_hashAlgorithm != null) { _hashAlgorithm.TransformFinalBlock(new byte[0], 0, 0); _trailingHeaders[ChecksumUtils.GetChecksumHeaderKey(_trailingChecksum)] = Convert.ToBase64String(_hashAlgorithm.Hash); } string chunkSignature; if (HeaderSigningResult is AWS4SigningResult) { var sortedTrailingHeaders = AWS4Signer.SortAndPruneHeaders(_trailingHeaders); var canonicalizedTrailingHeaders = AWS4Signer.CanonicalizeHeaders(sortedTrailingHeaders); var chunkStringToSign = TRAILING_HEADER_STRING_TO_SIGN_PREFIX + "\n" + HeaderSigningResult.ISO8601DateTime + "\n" + HeaderSigningResult.Scope + "\n" + PreviousChunkSignature + "\n" + AWSSDKUtils.ToHex(AWS4Signer.ComputeHash(canonicalizedTrailingHeaders), true); chunkSignature = AWSSDKUtils.ToHex(AWS4Signer.SignBlob(((AWS4SigningResult)HeaderSigningResult).GetSigningKey(), chunkStringToSign), true); } else // SigV4a { chunkSignature = Sigv4aSigner.SignTrailingHeaderChunk(_trailingHeaders, PreviousChunkSignature, (AWS4aSigningResult)HeaderSigningResult).PadRight(V4A_SIGNATURE_LENGTH, '*'); } var chunk = new StringBuilder(); // The order here must match the order of keys sent already in the X-Amz-Trailer header. foreach (var kvp in _trailingHeaders.OrderBy(kvp => kvp.Key)) { chunk.Append($"{kvp.Key}:{kvp.Value}{STREAM_NEWLINE}"); } chunk.Append($"{TRAILING_HEADER_SIGNATURE_KEY}:{chunkSignature}{STREAM_NEWLINE}"); chunk.Append(STREAM_NEWLINE); return(chunk.ToString()); }
private void ConstructOutputBufferChunk(int dataLen) { if (dataLen > 0 && dataLen < _inputBuffer.Length) { byte[] array = new byte[dataLen]; Buffer.BlockCopy(_inputBuffer, 0, array, 0, dataLen); _inputBuffer = array; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(dataLen.ToString("X", CultureInfo.InvariantCulture)); string data = "AWS4-HMAC-SHA256-PAYLOAD\n" + HeaderSigningResult.ISO8601DateTime + "\n" + HeaderSigningResult.Scope + "\n" + PreviousChunkSignature + "\n" + AWSSDKUtils.ToHex(AWS4Signer.ComputeHash(""), lowercase: true) + "\n" + ((dataLen > 0) ? AWSSDKUtils.ToHex(AWS4Signer.ComputeHash(_inputBuffer), lowercase: true) : "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); string str = PreviousChunkSignature = AWSSDKUtils.ToHex(AWS4Signer.SignBlob(HeaderSigningResult.SigningKey, data), lowercase: true); stringBuilder.Append(";chunk-signature=" + str); stringBuilder.Append("\r\n"); try { byte[] bytes = Encoding.UTF8.GetBytes(stringBuilder.ToString()); byte[] bytes2 = Encoding.UTF8.GetBytes("\r\n"); int num = 0; Buffer.BlockCopy(bytes, 0, _outputBuffer, num, bytes.Length); num += bytes.Length; if (dataLen > 0) { Buffer.BlockCopy(_inputBuffer, 0, _outputBuffer, num, dataLen); num += dataLen; } Buffer.BlockCopy(bytes2, 0, _outputBuffer, num, bytes2.Length); _outputBufferPos = 0; _outputBufferDataLen = bytes.Length + dataLen + bytes2.Length; } catch (Exception ex) { throw new AmazonClientException("Unable to sign the chunked data. " + ex.Message, ex); } }
/// <summary> /// Computes the derived signature for a chunk of data of given length in the input buffer, /// placing a formatted chunk with headers, signature and data into the output buffer /// ready for streaming back to the consumer. /// </summary> /// <param name="dataLen"></param> private void ConstructOutputBufferChunk(int dataLen) { // if the input wasn't sufficient to fill the buffer, size it // down to make the subseqent hashing/computations easier since // they don't take any length arguments if (dataLen > 0 && dataLen < _inputBuffer.Length) { var temp = new byte[dataLen]; Buffer.BlockCopy(_inputBuffer, 0, temp, 0, dataLen); _inputBuffer = temp; } var chunkHeader = new StringBuilder(); // variable-length size of the embedded chunk data in hex chunkHeader.Append(dataLen.ToString("X", CultureInfo.InvariantCulture)); string chunkSignature = ""; if (HeaderSigningResult is AWS4aSigningResult v4aHeaderSigningResult) { if (dataLen == 0) // _inputBuffer still contains previous chunk, but this is the final 0 content chunk so sign null { chunkSignature = Sigv4aSigner.SignChunk(null, PreviousChunkSignature, v4aHeaderSigningResult); } else { chunkSignature = Sigv4aSigner.SignChunk(new MemoryStream(_inputBuffer), PreviousChunkSignature, v4aHeaderSigningResult); } } else if (HeaderSigningResult is AWS4SigningResult v4HeaderSingingResult) // SigV4 { var chunkStringToSign = BuildChunkedStringToSign(CHUNK_STRING_TO_SIGN_PREFIX, v4HeaderSingingResult.ISO8601DateTime, v4HeaderSingingResult.Scope, PreviousChunkSignature, dataLen, _inputBuffer); chunkSignature = AWSSDKUtils.ToHex(AWS4Signer.SignBlob(v4HeaderSingingResult.GetSigningKey(), chunkStringToSign), true); } // For Sigv4a the chunk signature must be padded when being appended to the chunk metadata, // but not when being used as the input for the next chunk PreviousChunkSignature = chunkSignature; if (HeaderSigningResult is AWS4aSigningResult) { chunkHeader.Append(CHUNK_SIGNATURE_HEADER + chunkSignature.PadRight(V4A_SIGNATURE_LENGTH, '*')); } else // SigV4 { chunkHeader.Append(CHUNK_SIGNATURE_HEADER + chunkSignature); } chunkHeader.Append(CLRF); try { var header = Encoding.UTF8.GetBytes(chunkHeader.ToString()); var trailer = Encoding.UTF8.GetBytes(CLRF); var writePos = 0; Buffer.BlockCopy(header, 0, _outputBuffer, writePos, header.Length); writePos += header.Length; if (dataLen > 0) { Buffer.BlockCopy(_inputBuffer, 0, _outputBuffer, writePos, dataLen); writePos += dataLen; } Buffer.BlockCopy(trailer, 0, _outputBuffer, writePos, trailer.Length); _outputBufferPos = 0; _outputBufferDataLen = header.Length + dataLen + trailer.Length; } catch (Exception e) { throw new AmazonClientException("Unable to sign the chunked data. " + e.Message, e); } }