-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
351 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
# CASK 256-bit Primary Keys | ||
## Standard Backus-Naur Form (BNF) | ||
``` | ||
<key> ::= <payload-data> <checksum> | ||
<payload-data> ::= <random-data> <reserved> [<optional-fields>] <cask-signature> <provider-id> <timestamp> <key-type> <version> | ||
<random-data> ::= 42 * <base64url> <base64-two-zeros-suffix> ; The total random data comprises 256 bits encoded as 42 | ||
; characters x 6 bit bits of random data = 252 bits and | ||
; 1 character providing 4 bits of random data padded with 00b. | ||
<reserved> ::= '0' ; Reserved for future use. | ||
<optional-fields> ::= { <optional-field> } ; Zero or more 4-character (24 bit) sequences of optional data. | ||
<optional-field> ::= 4 * <base64url> ; Each optional field is 4 characters (24 bits). This keeps | ||
; data cleanly aligned along 3-byte/4-encoded character boundaries | ||
; facilitating readability of encoded form as well as byte-wise use. | ||
<cask-signature> ::= 'JQQJ' ; Fixed signature identifying the CASK key | ||
<provider-id> ::= 4 * <base64url> ; Provider identifier (24 bits) | ||
<timestamp> ::= <year> <month> <day> <hour> ; Timestamp components | ||
<year> ::= <base64url> ; Represents the year, 'A' (2024) to '_' (2087) | ||
<month> ::= 'A'..'L' ; For months January to December | ||
<day> ::= 'A'..'Z' | 'a'..'e' ; 'A' = day 1, 'B' = day 2, ... 'e' = day 30, ... 'e' = day 31 | ||
<hour> ::= 'A'..'X' ; Represents hours 0-23. 'A' = hour 0 (midnight), ... 'X' = hour 23. | ||
<key-type> ::= <256-bit-key> | <256-bit-hash> | <384-bit-hash> | ||
<256-bit-key> ::= 'A' | ||
<256-bit-hash> ::= 'H' | ||
<384-bit-hash> ::= 'I' | ||
<version> ::= 'A' | ||
<checksum> ::= <four-zeros-prefix-base64> 5 * <base64url> ; The checksum is 32 bits total encoded in six 6-bit characters. | ||
; The data starts with 0000b (four leading zero bit) and 2 bits | ||
; of checksum data followed by the remaining 30 bits of checksum. | ||
<base64url> ::= 'A'..'Z' | 'a'..'z' | '0'..'9' | '-' | '_' | ||
<four-zeros-prefix-base64> ::= 'A'..'D' ; Base64 characters starting with 0000b (indices 0-3). | ||
<base64-two-zeros-suffix> ::= 'A' | 'E' | 'I' | 'M' | 'Q' | 'U' | 'Y' | 'c' ; Base64 characters ending in 00b. These indices are all | ||
| 'g' | 'k' | 'o' | 's' | 'w' | '0' | '4' | '8' ; multiple of 4 (or the value of 0b), a fact that may be | ||
; useful in some contexts. | ||
``` | ||
## Byte-wise Rendering | ||
|Byte Range|Decimal|Hex|Binary|Description| | ||
|-|-|-|-|-| | ||
|decodedKey.Substring(32)|0...255|0x0...0xFF|00000000b...11111111b|256 bits of random data produced by a cryptographically secure RNG| | ||
|decodedKey[32]|0|0x00|00000000b| A reserved byte to enforce 3-byte alignment, set to zero. | ||
|decodedKey[33..^15]|0...255|0x0...0xFF|00000000b...11111111b|Provider-defined data, comprising 0 or more 3-byte sequences, of arbitrary interpretation. | ||
|decodedKey[^15..^12]| 37, 4, 9 |0x25, 0x04, 0x09| 00100101b, 00000100b, 00001001b | Decoded 'JQQJ' signature. | ||
|decodedKey[^12..^9]|0...255|0x0...0xFF|00000000b...11111111b| Provider identifier, e.g. , '0x4c', '0x44', '0x93' (base64 encoded as 'TEST') | ||
|decodedKey[^9..^6]||||Time stamp data encoded in 4 six-bit blocks for YMDH. | ||
|decodedKey[^6] >> 2|0, 28, 32|0x00, 0x1c, 0x20|00000000b...11111100b| Leading 6 bits comprises kind enum followed by 2 bits of reserved padding. key[key.Length - 6] & 0xfc == 0. | ||
|decodedKey[^5] >> 4]|0|0xFF|00000000b...11110000b| Leading 4 bits comprise 4 bits of reserved version information + 4 bits of zero padding (to preserve consistent rendering of the subsequence checksum data). | ||
|decodedKey[^4..]|0...255|0x0...0xFF|00000000b..11111111b|CRC32(key[..^4]) | ||
|
||
## Primary 256-bit Key Base64-Encoded Rendering | ||
|String Range|Text Value|Description| | ||
|-|-|-| | ||
|encodedKey[..42] | 'A'...'_' | 252 bits of randomized data generated by cryptographically secure RNG | ||
|encodedKey[42] | <base64-two-zeros-suffix> | 4 bits of randomized data followed by 2 zero bits. See the <base64-two-zeros-suffix> definition for legal values. | ||
|encodedKey[43] | 'A' | 6 bits of reserved data specified as 'A', base64 character index zero. | ||
|encodedKey[44..^20]|'A'...'_'|0 or more 4-character sequences comprising provider optional data, of arbitrary interpretation. | ||
|encodedKey[^20..^16]|'JQQJ'| Fixed CASK signature. | ||
|encodedKey[^16]|'A'...'Z'\|'a'...'z'| The first character of the provider signature which must be alphabetic (upper-case indicating a customer-managed as opposed to service managed secret). | ||
|encodedKey[^15..^12]|('A'...'Z'-\_)\|('a'...'z'-\_)| | The remaining three encoded characters. Any alphabetic characters must be consistently upper- or lower-case (to distinguish customer- vs. service-managed secrets). | ||
|encodedKey[^12]|'A'...'_'|Represents the year of key allocation, 'A' (2024) to '_' (2087)| | ||
|encodedKey[^11]|'A'...'L'|Represents the month of key allocation, 'A' (January) to 'L' (December)| | ||
|encodedKey[^10]|'A'...'Z'\|'a'..'e'|Represents the day of key allocation, 'A' (0) to 'e' (31)| | ||
|encodedKey[^9]|'A'...'X'|Represents the hour of key allocation, 'A' (hour 0 or midnight) to 'X' (hour 23). [TBD: This value could be used for half hour increments instead]. | ||
|encodedKey[^8]|'A', 'H', 'I'|Represents the key kind, a 256-bit primary key, HMAC256 or HMAC384. | ||
|encodedKey[^7]|'A'|Cask version 1.0 | ||
|encodedKey[^6]| 'A'...'D'| Four leading zero bits followed by the | ||
|encodedKey[^5..]|'A'...'_'|The final five encoded checksum characters. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
// Copyright (c) Microsoft. All rights reserved. | ||
// Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
|
||
namespace CommonAnnotatedSecurityKeys; | ||
internal enum CaskVersion : byte | ||
{ | ||
/// <summary> | ||
/// Specifies version 1.0.0 of CASK. | ||
/// </summary> | ||
OneZeroZero, | ||
|
||
Reserved = 0xfe, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
// Copyright (c) Microsoft. All rights reserved. | ||
// Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
|
||
namespace CommonAnnotatedSecurityKeys; | ||
|
||
internal enum BytewiseKeyKind : byte | ||
{ | ||
/// <summary> | ||
/// Specifies a 256-bit primary API or other security key. The enum | ||
/// value '0' comprises the base64 index that maps to character 'A'. | ||
/// </summary> | ||
Key256Bit = ('A' - 'A') << 2, // Base64 index 0 == 'A' | ||
|
||
/// <summary> | ||
/// Specifies a CASK hashed signature that incorporates a Message | ||
/// Authentication code of a derivation input generated by SHA-256. | ||
/// </summary> | ||
Hash256Bit = ('H' - 'A') << 2, // Base64 index 7 == 'H', << 2 == 28, 0x1c, 0b000 11100 | ||
|
||
/// <summary> | ||
/// Specifies a CASK hashed signature that incorporates a Message | ||
/// Authentication code of a derivation input generated by SHA-384. | ||
/// </summary> | ||
Hash384Bit = ('I' - 'A') << 2, // Base64 index 7 == 'H', << 2 == 32, 0x20, 0b0010 0000 | ||
} | ||
|
||
internal enum EncodedKeyKind : byte | ||
{ | ||
/// <summary> | ||
/// Specifies a 256-bit primary API or other security key. The enum | ||
/// value '0' comprises the base64 index that maps to character 'A'. | ||
/// </summary> | ||
Key256Bit = 'A' - 'A', // Base64 index 0 == 'A' | ||
|
||
/// <summary> | ||
/// Specifies a CASK hashed signature that incorporates a Keyed Hash | ||
/// Message Authenticode of a derivation input generated by SHA-256 | ||
/// (HMAC-SHA-256) along with other CASK data such as the generated | ||
/// C3ID of the CASK key used to initialize the HMAC instance. | ||
/// </summary> | ||
Hash256Bit = 'H' - 'A', // Base64 index 7 == 'H', 7, 0x7, 0b0111 | ||
|
||
/// <summary> | ||
/// Specifies a CASK hashed signature that incorporates a Keyed Hash | ||
/// Message Authenticode of a derivation input generated by SHA-384 | ||
/// (HMAC-SHA-384) along with other CASK data such as the generated | ||
/// C3ID of the CASK key used to initialize the HMAC instance. | ||
/// </summary> | ||
Hash384Bit = 'I' - 'A', // Base64 index 7 == 'I', 8, 0x8, 0b1000 | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// Copyright (c) Microsoft. All rights reserved. | ||
// Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
|
||
using System.Buffers.Text; | ||
|
||
namespace CommonAnnotatedSecurityKeys; | ||
|
||
internal readonly struct ThreeByteSequence | ||
{ | ||
public ThreeByteSequence(ReadOnlySpan<byte> bytes) | ||
{ | ||
if (bytes.Length != 3) | ||
{ | ||
throw new ArgumentException("Three-byte sequence must be exactly three bytes long.", nameof(bytes)); | ||
} | ||
Bytes = bytes.ToArray(); | ||
Encoded = Convert.ToBase64String(Bytes); | ||
} | ||
|
||
public byte[] Bytes { get; } | ||
|
||
public string Encoded { get; } | ||
|
||
public byte FirstSixBits => (byte)(Bytes[0] >> 2); | ||
|
||
public byte SecondSixBits => (byte)(((Bytes[0] & 0b00000011) << 4) | Bytes[1] >> 4); | ||
|
||
public byte ThirdSixBits => (byte)(((Bytes[1] & 0b00001111) << 2) | Bytes[2] >> 6); | ||
|
||
public byte FourthSixBits => (byte)(Bytes[2] & 0b00111111); | ||
} |
Oops, something went wrong.