diff options
author | chai <215380520@qq.com> | 2023-10-12 22:09:49 +0800 |
---|---|---|
committer | chai <215380520@qq.com> | 2023-10-12 22:09:49 +0800 |
commit | 8d2a2cd5de40e2b94ef5007c32832ed9a063dc40 (patch) | |
tree | a63dfbe815855925c9fb8f2804bd6ccfeffbd2eb /Tools/Hazel-Networking/Hazel/Dtls/PrfSha256.cs | |
parent | dd0c5d50e377d9be1e728463670908a6c9d2c14f (diff) |
+hazel-networking
Diffstat (limited to 'Tools/Hazel-Networking/Hazel/Dtls/PrfSha256.cs')
-rw-r--r-- | Tools/Hazel-Networking/Hazel/Dtls/PrfSha256.cs | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/Tools/Hazel-Networking/Hazel/Dtls/PrfSha256.cs b/Tools/Hazel-Networking/Hazel/Dtls/PrfSha256.cs new file mode 100644 index 0000000..1fa7f17 --- /dev/null +++ b/Tools/Hazel-Networking/Hazel/Dtls/PrfSha256.cs @@ -0,0 +1,84 @@ +using System.Text; +using System.Security.Cryptography; + +namespace Hazel.Dtls +{ + /// <summary> + /// Common Psuedorandom Function labels for TLS + /// </summary> + public struct PrfLabel + { + public static readonly ByteSpan MASTER_SECRET = LabelToBytes("master secert"); + public static readonly ByteSpan KEY_EXPANSION = LabelToBytes("key expansion"); + public static readonly ByteSpan CLIENT_FINISHED = LabelToBytes("client finished"); + public static readonly ByteSpan SERVER_FINISHED = LabelToBytes("server finished"); + + /// <summary> + /// Convert a text label to a byte sequence + /// </summary> + public static ByteSpan LabelToBytes(string label) + { + return Encoding.ASCII.GetBytes(label); + } + } + + /// <summary> + /// The P_SHA256 Psuedorandom Function + /// </summary> + public struct PrfSha256 + { + /// <summary> + /// Expand a secret key + /// </summary> + /// <param name="output">Output span. Length determines how much data to generate</param> + /// <param name="key">Original key to expand</param> + /// <param name="label">Label (treated as a salt)</param> + /// <param name="initialSeed">Seed for expansion (treated as a salt)</param> + public static void ExpandSecret(ByteSpan output, ByteSpan key, string label, ByteSpan initialSeed) + { + ExpandSecret(output, key, PrfLabel.LabelToBytes(label), initialSeed); + } + + /// <summary> + /// Expand a secret key + /// </summary> + /// <param name="output">Output span. Length determines how much data to generate</param> + /// <param name="key">Original key to expand</param> + /// <param name="label">Label (treated as a salt)</param> + /// <param name="initialSeed">Seed for expansion (treated as a salt)</param> + public static void ExpandSecret(ByteSpan output, ByteSpan key, ByteSpan label, ByteSpan initialSeed) + { + ByteSpan writer = output; + + byte[] roundSeed = new byte[label.Length + initialSeed.Length]; + label.CopyTo(roundSeed); + initialSeed.CopyTo(roundSeed, label.Length); + + byte[] hashA = roundSeed; + + using (HMACSHA256 hmac = new HMACSHA256(key.ToArray())) + { + byte[] input = new byte[hmac.OutputBlockSize + roundSeed.Length]; + new ByteSpan(roundSeed).CopyTo(input, hmac.OutputBlockSize); + + while (writer.Length > 0) + { + // Update hashA + hashA = hmac.ComputeHash(hashA); + + // generate hash input + new ByteSpan(hashA).CopyTo(input); + + ByteSpan roundOutput = hmac.ComputeHash(input); + if (roundOutput.Length > writer.Length) + { + roundOutput = roundOutput.Slice(0, writer.Length); + } + + roundOutput.CopyTo(writer); + writer = writer.Slice(roundOutput.Length); + } + } + } + } +} |