This file describes the technical details of the calculation and verification of signatures. The first part explains the cryptographic basics. The second part specifies the individual calculation steps.
This system works with digital signatures. The following steps are required to create a digital signature:
- selection of an asymmetric encryption method such as RSA or elliptic curves.
- selection of a cryptographically secure hash method.
First, the hash method is used to determine a cryptographically secure checksum for the data to be signed.
An asymmetric encryption method uses a key pair consisting of a private and a public key. The following rules apply with regard to encryption and decryption:
- What is encrypted with the public key can only be decrypted with the private key.
- What is encrypted with the private key can only be decrypted with the public key.
As the name suggests, the public key is known and is not kept secret. The private key must be kept secret.
For the signature, the hash value determined is encrypted with the private - i.e. secret - key of the creator. The hash value encrypted in this way represents the digital signature.
The person who wants to verify a digital signature decrypts the digital signature with the public - i.e. known - key of the creator. They then calculate the hash value of the data using the same hash procedure. Then the decrypted hash value from the signature is compared to the hash value it has calculated itself. If the two hash values match, the digital signature is valid, otherwise it is not.
If the verification is successful, it is ensured that the creator of the signature has used the private key that matches the public key.
The security of this procedure rests on two pillars:
- The hash procedure ensures that an attacker cannot change the data in such a way that the same hash value is created with the changed data.
- The encryption method ensures that the value of the private key cannot be deduced from knowledge of the public key.
The SHA3-512 method is used to calculate the hash value, i.e. SHA-3 with a hash length of 512 bits (64 bytes). This method was standardized by NIST and is currently the most secure hash method with a very long and therefore still secure hash value length in the long term.
The signature methods used are Ed25519 and ECDSA with the curve P-521.
Both methods use elliptic curves as an asymmetric encryption method. Elliptic curves are currently and in the foreseeable future secure against attacks by classical computers. Theoretically, they can be attacked by quantum computers. However, elliptic curves are more difficult to attack by quantum computers than RSA, as the attack has a higher complexity. If a concrete threat to elliptic curves becomes known, the system can be changed at any time so that a quantum computer-safe signature system such as CRYSTALS-Dilithium, FALCON or SPHINCS+ is used. At present, however, there are hardly any libraries available for the use of these systems.
At the same time, elliptic curves are more efficient in terms of resource consumption due to their significantly shorter key lengths compared to RSA. In summary, there are currently no known effective attacks on elliptic curves.
The Ed25519 method is based on the elliptic curve Curve25519, which is the most secure known elliptic curve and can be computed efficiently.
The ECDSA method with the P-521 curve, on the other hand, uses the P-521 curve standardized by NIST with the ECDSA standard also created by NIST. The method is significantly less efficient than Ed25519, but is available in many programming languages.
The following section describes how the individual calculations are performed.
Whenever the content of bytes is specified, these are given in hexadecimal notation.
Two values are used several times so that they are described here in advance:
Counters or lengths are used for the calculation. Their values are always used with as many bytes as necessary and no more. The bytes are specified in the so-called big-endian format.
To illustrate this, here are a few examples of values with their encoding in variable length:
value | encoding (hexadecimal) |
---|---|
0 |
00 |
1 |
01 |
255 |
ff |
300 |
01 2c |
65432 |
ff 98 |
100000 |
01 86 a0 |
The context ID is both data in the file and a key for calculating the hash values. Direct use of the context ID in the calculation of the hash values enables manipulation of the file. A key is therefore calculated from the context ID according to the following rule. Due to the non-linear dependency of this key on the context ID, manipulation is no longer possible.
The context key is calculated from the context ID as follows:
- The characters of the
ContextId
are coded inUTF-8
. - As described in the previous section, their length is appended in variable length, which is referred to below as the "extended context ID".
- Then the SHA-3-256 value of the extended context ID rotated around in the byte sequence is calculated.
- This creates a key from the following values:
- Constant byte sequence
6f 00 11 21 3d 31 c2 3b c3 69 ab 0b 6d 8e 42 35
. - Hash value just calculated.
- Constant byte sequence
30 2d 15 d7 37 d5 b1 df 45 ee 30 bc e0 0b 89 cc
.
- Constant byte sequence
- This key is used as the key for an HMAC-SHA-3-512 procedure.
- The HMAC value of the context ID is calculated.
- This produces a key with the following values:
- The first 32 bytes of the HMAC value.
- The extended context ID.
- The last 32 bytes of the HMAC value.
- The key calculated in this way is used in the calculation of all hash values.
- First, the first half of the key is fed into the hash value.
- Then all the data is fed into the hash value.
- Finally, the second half of the key is fed into the hash value.
- If the key length is odd, the first half of the key is one byte shorter than the second half.
An example shows this calculation rule using concrete values:
- The context id is
transfer
. - The context bytes are then
c3 9c 62 65 72 66 c3 bc 68 72 75 6e 67
and have the length 13 (0d
). - The extended context ID has the value
c3 9c 62 65 72 66 c3 bc 68 72 75 6e 67 0d
. - Then the SHA-3-256 value of the following byte sequence is calculated
0d 67 6e 75 72 68 bc c3 66 72 65 62 9c c3
:86 3a fd 35 1e 70 d5 07 76 93 b5 73 6f 9b 7f 7e 8b ec a2 13 b1 56 a6 f5 91 6e 35 83 84 9a 17 ff
. - This results in the HMAC key:
6f 00 11 21 3d 31 c2 3b c3 69 ab 0b 6d 8e 42 35 86 3a fd 35 1e 70 d5 07 76 93 b5 73 6f 9b 7f 7e 8b ec a2 13 b1 56 a6 f5 91 6e 35 83 84 9a 17 ff 30 2d 15 d7 37 d5 b1 df 45 ee 30 bc e0 0b 89 cc
. - This is used to calculate the SHA-3-512 HMAC value of the byte sequence
c3 9c 62 65 72 66 c3 bc 68 72 75 6e 67
:8c 25 5a 6c 5a 75 d2 ab bc 34 c7 2f 38 a8 da db 7b 39 97 47 b1 9e 3e e8 d3 9a f9 cf 83 9a 39 03 ad 02 d1 0f 9a 8d ae 22 6d 23 14 07 5e bc 81 c7 d3 eb 4c 71 a8 92 e7 c9 a5 6a 86 82 e4 fe f9 e7
. - The context key is now formed from the first 32 bytes of the HMAC value, the extended context ID and the last 32 bytes of the HMAC value:
8c 25 5a 6c 5a 75 d2 ab bc 34 c7 2f 38 a8 da db 7b 39 97 47 b1 9e 3e e8 d3 9a f9 cf 83 9a 39 03 c3 9c 62 65 72 66 c3 bc 68 72 75 6e 67 0d ad 02 d1 0f 9a 8d ae 22 6d 23 14 07 5e bc 81 c7 d3 eb 4c 71 a8 92 e7 c9 a5 6a 86 82 e4 fe f9 e7
.
The byte sequence c3 9c 62 65 72 66 c3 bc 68 72 75 6e 67
is thus the context key 8c 25 5a 6c 5a 75 d2 ab bc 34 c7 2f 38 a8 da db 7b 39 97 47 b1 9e 3e e8 d3 9a f9 cf 83 9a 39 03 c3 9c 62 65 72 66 c3 bc 68 72 75 6e 67 0d ad 02 d1 0f 9a 8d ae 22 6d 23 14 07 5e bc 81 c7 d3 eb 4c 71 a8 92 e7 c9 a5 6a 86 82 e4 fe f9 e7
.
In the hash value calculations in this example, the byte sequence 8c 25 5a 6c 5a 75 d2 ab bc 34 c7 2f 38 a8 da db 7b 39 97 47 b1 9e 3e e8 d3 9a f9 cf 83 9a 39 03 c3 9c 62 65 72 66 c3
is always fed in at the beginning and the byte sequence bc 68 72 75 6a 75 d2 ab bc 34 c7 2f 38 a8 da db 7b 39 97 47 b1 9e 3e e8 d3 9a f9 cf 83 9a 39 03 c3 9c 62 65 72 66 c3
is fed in at the end. sequence bc 68 72 75 6e 67 0d ad 02 d1 0f 9a 8d ae 22 6d 23 14 07 5e bc 81 c7 d3 eb 4c 71 a8 92 e7 c9 a5 6a 86 82 e4 fe f9 e7
.
The hash values of the files are calculated by passing the following values to the hash algorithm SHA-3-512 in the following order:
- First half of the context key
- Bytes of the file content
- Length of the file with variable length
- Second half of the context key
The hash value is then read out and used for the file signature.
The following procedure is used for the hash value of the signature file:
- A counter is initialized with the value
0
. - Before each value, the counter is incremented by 1 and its value is passed in variable length.
- This is followed by the value itself.
- This is followed by the length of the value in variable length.
The hash value therefore depends on the position of a value.
The byte values are always used and not the coding. So if a value in the signature file is encoded with Base32, the bytes that it represents are used and not the encoded values.
The values are fed in in the following order:
- First half of the context key
- Format identifier as a binary value, i.e.
01
for the format with the identifier `1 - Context ID
- Byte values of the public key
- timestamp text
- Computer name
- Signature type as a binary value, i.e.
01
forEd25519
and02
for ECDSAP521 - The file names are sorted alphabetically and then fed in as follows:
- UTF-8 encoded name of the file
- Byte values of the file signature
- Second half of the context key
The hash value is then taken from these values.
To illustrate this, the slightly modified example from the documentation is used here to show which bytes are fed into the hash algorithm:
This is the content of the example file:
{
"format": 1,
"contextId": "Überführung",
"publicKey": "HxVJVrrjQcgfvhPxJ45chrQrRCFWmgJ5JH8JGMv6xxj23xjH8P52",
"timestamp": "2024-02-25 13:37:22 +05:30",
"hostname": "BuildHost",
"signatureType": 1,
"fileSignatures": {
"common.go": "mpmQrxWxqgwPmw54gm6hPMMv8pW4MFRjmJrfqH99H4q39vQgxVJ3vcj2qpcWPqVr337VRPJJ4X3CP8WR39VwgJQjJfW23RPWmhPQW2R",
"filesigner": "WWQmj6822QrqcwP2j75pw2xf3Hvjpv97H2cXQqVx97WmGP77c25H28PQcjCCQv9MP8xp2cq46R9prQpqGVrGRCVV7gQJw6Q3r3cpp3R",
"filesigner.exe": "3W9rJ3WGx6mVFFXjXQmMvJ4jw9XhQ7j3VGmhcRj2pF42JgGvP2frhQXg6V5QQvwPqxmcx7Wg86C7v3v4H9qWqPwCMcvpgxxJv3M7442",
"maphelper/map_helper.go": "HXqJRpVH69Xpxgp9f9FpWMXQxF5rJPPGwFC2Hcp9hG979f4FR8Fgv6fG4mPqQxpW9x6R9RRvWXgGF5rpHW83gCGQr2hPfHMJ6G34J52",
"set/set.go": "fvw537rpJq3QHHgqxFW8J85VCvjcgFrwRh8gH5wPh266f65V8XmjqGJG9pJ98xm9vMGfFp2jpr6qw4cv46G9vPX5J8F4cR9vG3M8R3R",
},
"dataSignature": "PCvCgQ9PFjf6hPCh4RvPHvCp47VghrmX96fwC2r43VhxJCXHXR4v2QX8wrwFjQRm4FqG56cM9wf4pf4hhMrR2JpM88Pf8pFxvmRhj2j"
}
For the example, the value of the context ID should be Überführung
.
This is German and means transfer
.
This word is used here to demonstrate the encoding of non-ASCII characters in UTF-8.
The context bytes are then c3 9c 62 65 72 66 c3 bc 68 72 75 6e 67
and have the length 13 (0d
).
The following values are then passed to the hash algorithm:
Bytes | Meaning |
---|---|
8c 25 5a 6c 5a 75 d2 ab bc 34 c7 2f 38 a8 da db 7b 39 97 47 b1 9e 3e e8 d3 9a f9 cf 83 9a 39 03 c3 9c 62 65 72 66 c3 |
1. half of the context key |
01 |
Counter |
01 |
Format ID |
01 |
Length of format ID |
02 |
Counter |
c3 9c 62 65 72 66 c3 bc 68 72 75 6e 67 |
Context ID |
0d |
Length of context ID |
03 |
Counter |
5f e2 c8 f3 98 7d 2d 5e dd df 60 87 4b f1 fc 82 13 2c d9 83 62 cc c5 37 a4 ff f0 00 ff 0b 33 86 |
Public key |
20 |
Length of context ID |
04 |
Counter |
32 30 32 34 2d 30 32 2d 32 35 20 31 33 3a 33 37 3a 32 32 20 2b 30 35 3a 33 30 |
Timestamp |
1a |
Length of timestamp |
05 |
Counter |
42 75 69 6c 64 48 6f 73 74 |
Hostname |
09 |
Length of Hostname |
06 |
Counter |
01 |
Signature type |
01 |
Length of signature type |
07 |
Counter |
63 6f 6d 6d 6f 6e 2e 67 6f |
1. file name |
09 |
Length of 1. file name |
08 |
Counter |
ce, b2, fe, 7e, 5f, dd, bc, ec, f8, 62, b6, 49, 77, 35, bd, 36, a4, 26, a6, 18, cb, 39, 5d, ac, e7, 58, b6, 13, f5, f6, fc, 58, 1e, d3, 00, de, a9, 27, 6e, 3c, 08, 4b, 18, 39, 8c, 14, c2, 87, 1a, 50, 09, e3, eb, 31, f8, 65, 64, 00, c1, d2, cd, dc, f9, 02 |
Signature of 1. file |
40 |
Length of signature of 1. file name |
09 |
Counter |
66 69 6c 65 73 69 67 6e 65 72 |
2. file name |
0a |
Length of 2. file name |
0a |
Counter |
94, 9f, 9c, 10, c0, 03, f9, ba, 79, c0, c1, 47, af, 03, f5, 0a, fb, 8d, 74, e5, 58, 29, 37, ee, 3f, 39, 65, 95, 38, a5, a0, 06, b0, 19, cf, a6, 10, 87, f4, ed, 71, bf, a0, 53, 62, 24, 0f, ae, 3f, 5b, 54, 78, a8, 22, 31, 2d, 9e, cf, 11, e1, e0, 69, ad, 06 |
Signature of 2. file |
40 |
Length of signature of 2. file name |
0b |
Counter |
66 69 6c 65 73 69 67 6e 65 72 2e 65 78 65 |
3. file name |
0e |
Length of 3. file name |
0c |
Counter |
0c, 8f, c6, 06, 4a, f9, 33, 14, a6, 78, 9b, f2, de, b0, 58, f1, e7, 77, 97, 01, 8a, b3, 7a, 43, 00, d2, 44, 06, 59, 5d, 70, 2b, cb, be, 76, 24, 46, f7, f7, ce, df, f3, 4f, 96, 56, 31, 10, 5e, 87, a2, 59, f7, 2d, bb, c8, 6d, 3b, ab, 7f, ec, e8, 5a, 51, 08 |
Signature of 3. file |
40 |
Length of signature of 3. file name |
0d |
Counter |
6d 61 70 68 65 6c 70 65 72 2f 6d 61 70 5f 68 65 6c 70 65 72 6e 65 72 |
4. file name |
17 |
Length of 4. file name |
0e |
Counter |
5c, f6, c8, 6a, 2b, 21, e7, af, db, 47, a9, d3, a9, 36, 6f, fa, 47, c6, 39, ca, f2, 50, 05, d3, 47, ba, 8e, 53, d4, 49, 81, 93, 6e, 92, aa, 16, 5d, b7, ff, 52, 3f, c9, 03, c2, 1d, 94, ec, a4, 8f, 9a, 5c, 8c, 1b, 21, 4f, e0, 2e, ea, ad, ac, 22, 82, 26, 0c |
Signature of 4. file |
40 |
Length of signature of 4. file name |
0f |
Counter |
73 65 74 2f 73 65 74 6e 65 72 |
5. file name |
0a |
Length of 5. file name |
10 |
Counter |
af, 7c, 30, 97, 9a, 66, c2, f5, ae, db, fa, 64, 66, 18, 71, 47, 71, 4b, 27, 9e, 85, cd, 65, 8f, ce, b8, 08, 4a, 90, 71, 34, f3, 8d, a9, 8a, 3e, 98, 73, 7f, 27, eb, 55, 54, e8, 18, d7, 09, bf, 0a, 9d, 11, 14, 7e, ba, 63, 61, 92, 2a, 40, fd, 50, 5a, 68, 06 |
Signature of 5. file |
40 |
Length of signature of 5. file name |
bc 68 72 75 6e 67 0d ad 02 d1 0f 9a 8d ae 22 6d 23 14 07 5e bc 81 c7 d3 eb 4c 71 a8 92 e7 c9 a5 6a 86 82 e4 fe f9 e7 |
2. half of context key |
The SHA3-512 hash value is then generated, which is used to sign the signature file.
The hash values are required to generate the signature.
In the ECDSAP521 procedure, they are used directly as described in the Hash values of files section.
With the Ed25519 procedure, however, this is much more complex. Ed25519 requires the complete data to be signed and not just its hash values, as it calculates two hash values itself and has to go over the entire data twice to do so. However, this is not possible here, as the files can be of any size and Ed25519 does not support a stream interface.
RFC8032 describes a variant 'Ed25519ph', where 'ph' stands for pre-hashed.
This procedure only expects a hash value.
A text with a length of 32 bytes is placed in front of the hash value and the signature of this data is calculated.
Ed25519ph
is not used here.
Instead, the following procedure is used:
Ed25519
is used.- Two constants are added to the left and right of the hash value.
- The signature of this extended hash value is then calculated.
The two constants have the following values:
location | constant |
---|---|
Left | 44 97 72 da b6 a9 2b 43 c5 06 c4 92 06 37 58 e4 |
Right | b8 16 17 05 8d 38 c4 50 2b 01 2f f9 49 9e 2d dc |
This procedure is similar to Ed25519ph
, except that the 32 additional bytes are divided into 16 bytes each to the left and right of the hash value and other constants are used.
Example:
The hash value ea f8 3a 32 32 e6 d0 68 ed 42 cb cf c4 7b b5 4b 28 3e c3 b6 66 54 cc c0 4e 4b 07 14 dd 02 f2 b9 58 e5 9b 05 20 aa c3 bb b5 7f d3 10 ac f9 e9 ab 5a ff 56 fa 20 5e 44 26 a0 1c 0c 3d 2a 4a ef 77
is to be signed.
The signature of the following data is then calculated using this procedure:
44 97 72 da b6 a9 2b 43 c5 06 c4 92 06 37 58 e4 ea f8 3a 32 32 e6 d0 68 ed 42 cb cf c4 7b b5 4b 28 3e c3 b6 66 54 cc c0 4e 4b 07 14 dd 02 f2 b9 58 e5 9b 05 20 aa c3 bb b5 7f d3 10 ac f9 e9 ab 5a ff 56 fa 20 5e 44 26 a0 1c 0c 3d 2a 4a ef 77 b8 16 17 05 8d 38 c4 50 2b 01 2f f9 49 9e 2d dc