Add SBOM, symbols, traces, and VEX files for CVE-2022-21661 SQLi case
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
- Created CycloneDX and SPDX SBOM files for both reachable and unreachable images. - Added symbols.json detailing function entry and sink points in the WordPress code. - Included runtime traces for function calls in both reachable and unreachable scenarios. - Developed OpenVEX files indicating vulnerability status and justification for both cases. - Updated README for evaluator harness to guide integration with scanner output.
This commit is contained in:
169
src/__Libraries/StellaOps.Cryptography/DefaultCryptoHash.cs
Normal file
169
src/__Libraries/StellaOps.Cryptography/DefaultCryptoHash.cs
Normal file
@@ -0,0 +1,169 @@
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
|
||||
namespace StellaOps.Cryptography;
|
||||
|
||||
public sealed class DefaultCryptoHash : ICryptoHash
|
||||
{
|
||||
private readonly IOptionsMonitor<CryptoHashOptions> options;
|
||||
private readonly ILogger<DefaultCryptoHash> logger;
|
||||
|
||||
[ActivatorUtilitiesConstructor]
|
||||
public DefaultCryptoHash(
|
||||
IOptionsMonitor<CryptoHashOptions> options,
|
||||
ILogger<DefaultCryptoHash>? logger = null)
|
||||
{
|
||||
this.options = options ?? throw new ArgumentNullException(nameof(options));
|
||||
this.logger = logger ?? NullLogger<DefaultCryptoHash>.Instance;
|
||||
}
|
||||
|
||||
internal DefaultCryptoHash(CryptoHashOptions? options = null)
|
||||
: this(new StaticOptionsMonitor(options ?? new CryptoHashOptions()), NullLogger<DefaultCryptoHash>.Instance)
|
||||
{
|
||||
}
|
||||
|
||||
public byte[] ComputeHash(ReadOnlySpan<byte> data, string? algorithmId = null)
|
||||
{
|
||||
var algorithm = NormalizeAlgorithm(algorithmId);
|
||||
return algorithm switch
|
||||
{
|
||||
HashAlgorithms.Sha256 => ComputeSha256(data),
|
||||
HashAlgorithms.Sha512 => ComputeSha512(data),
|
||||
HashAlgorithms.Gost3411_2012_256 => GostDigestUtilities.ComputeDigest(data, use256: true),
|
||||
HashAlgorithms.Gost3411_2012_512 => GostDigestUtilities.ComputeDigest(data, use256: false),
|
||||
_ => throw new InvalidOperationException($"Unsupported hash algorithm {algorithm}.")
|
||||
};
|
||||
}
|
||||
|
||||
public string ComputeHashHex(ReadOnlySpan<byte> data, string? algorithmId = null)
|
||||
=> Convert.ToHexString(ComputeHash(data, algorithmId)).ToLowerInvariant();
|
||||
|
||||
public string ComputeHashBase64(ReadOnlySpan<byte> data, string? algorithmId = null)
|
||||
=> Convert.ToBase64String(ComputeHash(data, algorithmId));
|
||||
|
||||
public async ValueTask<byte[]> ComputeHashAsync(Stream stream, string? algorithmId = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(stream);
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var algorithm = NormalizeAlgorithm(algorithmId);
|
||||
return algorithm switch
|
||||
{
|
||||
HashAlgorithms.Sha256 => await ComputeShaStreamAsync(HashAlgorithmName.SHA256, stream, cancellationToken).ConfigureAwait(false),
|
||||
HashAlgorithms.Sha512 => await ComputeShaStreamAsync(HashAlgorithmName.SHA512, stream, cancellationToken).ConfigureAwait(false),
|
||||
HashAlgorithms.Gost3411_2012_256 => await ComputeGostStreamAsync(use256: true, stream, cancellationToken).ConfigureAwait(false),
|
||||
HashAlgorithms.Gost3411_2012_512 => await ComputeGostStreamAsync(use256: false, stream, cancellationToken).ConfigureAwait(false),
|
||||
_ => throw new InvalidOperationException($"Unsupported hash algorithm {algorithm}.")
|
||||
};
|
||||
}
|
||||
|
||||
public async ValueTask<string> ComputeHashHexAsync(Stream stream, string? algorithmId = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var bytes = await ComputeHashAsync(stream, algorithmId, cancellationToken).ConfigureAwait(false);
|
||||
return Convert.ToHexString(bytes).ToLowerInvariant();
|
||||
}
|
||||
|
||||
private static byte[] ComputeSha256(ReadOnlySpan<byte> data)
|
||||
{
|
||||
Span<byte> buffer = stackalloc byte[32];
|
||||
SHA256.HashData(data, buffer);
|
||||
return buffer.ToArray();
|
||||
}
|
||||
|
||||
private static byte[] ComputeSha512(ReadOnlySpan<byte> data)
|
||||
{
|
||||
Span<byte> buffer = stackalloc byte[64];
|
||||
SHA512.HashData(data, buffer);
|
||||
return buffer.ToArray();
|
||||
}
|
||||
|
||||
private static async ValueTask<byte[]> ComputeShaStreamAsync(HashAlgorithmName name, Stream stream, CancellationToken cancellationToken)
|
||||
{
|
||||
using var incremental = IncrementalHash.CreateHash(name);
|
||||
var buffer = ArrayPool<byte>.Shared.Rent(128 * 1024);
|
||||
try
|
||||
{
|
||||
int bytesRead;
|
||||
while ((bytesRead = await stream.ReadAsync(buffer.AsMemory(0, buffer.Length), cancellationToken).ConfigureAwait(false)) > 0)
|
||||
{
|
||||
incremental.AppendData(buffer, 0, bytesRead);
|
||||
}
|
||||
|
||||
return incremental.GetHashAndReset();
|
||||
}
|
||||
finally
|
||||
{
|
||||
ArrayPool<byte>.Shared.Return(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
private static async ValueTask<byte[]> ComputeGostStreamAsync(bool use256, Stream stream, CancellationToken cancellationToken)
|
||||
{
|
||||
var digest = GostDigestUtilities.CreateDigest(use256);
|
||||
var buffer = ArrayPool<byte>.Shared.Rent(128 * 1024);
|
||||
try
|
||||
{
|
||||
int bytesRead;
|
||||
while ((bytesRead = await stream.ReadAsync(buffer.AsMemory(0, buffer.Length), cancellationToken).ConfigureAwait(false)) > 0)
|
||||
{
|
||||
digest.BlockUpdate(buffer, 0, bytesRead);
|
||||
}
|
||||
|
||||
var output = new byte[digest.GetDigestSize()];
|
||||
digest.DoFinal(output, 0);
|
||||
return output;
|
||||
}
|
||||
finally
|
||||
{
|
||||
ArrayPool<byte>.Shared.Return(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
private string NormalizeAlgorithm(string? algorithmId)
|
||||
{
|
||||
var defaultAlgorithm = options.CurrentValue?.DefaultAlgorithm;
|
||||
if (!string.IsNullOrWhiteSpace(algorithmId))
|
||||
{
|
||||
return algorithmId.Trim().ToUpperInvariant();
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(defaultAlgorithm))
|
||||
{
|
||||
return defaultAlgorithm.Trim().ToUpperInvariant();
|
||||
}
|
||||
|
||||
return HashAlgorithms.Sha256;
|
||||
}
|
||||
|
||||
private sealed class StaticOptionsMonitor : IOptionsMonitor<CryptoHashOptions>
|
||||
{
|
||||
private readonly CryptoHashOptions options;
|
||||
|
||||
public StaticOptionsMonitor(CryptoHashOptions options)
|
||||
=> this.options = options;
|
||||
|
||||
public CryptoHashOptions CurrentValue => options;
|
||||
|
||||
public CryptoHashOptions Get(string? name) => options;
|
||||
|
||||
public IDisposable OnChange(Action<CryptoHashOptions, string> listener)
|
||||
=> NullDisposable.Instance;
|
||||
|
||||
private sealed class NullDisposable : IDisposable
|
||||
{
|
||||
public static readonly NullDisposable Instance = new();
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user