The two halves mixed into one AES-256 key. `source` is the exact DeviceKeySource to bind to (DeviceKeySourceNone for passphrase only), and a passphrase of "" means there is none. False when neither half exists — deriving from the label and the salt alone would be a key anyone can compute, which is worse than refusing.
| 151 | // deriving from the label and the salt alone would be a key anyone can |
| 152 | // compute, which is worse than refusing. |
| 153 | bool deriveKey(int source, const char* passphrase, const uint8_t* salt, uint32_t iterations, uint8_t* outKey) |
| 154 | { |
| 155 | const bool hasPass = passphrase != nullptr && passphrase[0] != '\0'; |
| 156 | if (source == DeviceKeySourceNone && !hasPass) { |
| 157 | return false; |
| 158 | } |
| 159 | |
| 160 | // "CKPTSEAL1" || dk || pk, with a zero-filled half for whichever is |
| 161 | // absent, so the message stays a fixed length and no two different |
| 162 | // (device, passphrase) pairs can produce the same bytes. |
| 163 | uint8_t material[9 + kKeySize + kKeySize]; |
| 164 | memset(material, 0, sizeof(material)); |
| 165 | memcpy(material, "CKPTSEAL1", 9); |
| 166 | bool ok = true; |
| 167 | |
| 168 | if (source != DeviceKeySourceNone && ScriptHost::get().deviceSecret(material + 9, source) < 0) { |
| 169 | ok = false; |
| 170 | } |
| 171 | |
| 172 | if (ok && hasPass) { |
| 173 | const mbedtls_md_info_t* md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); |
| 174 | mbedtls_md_context_t md_ctx; |
| 175 | mbedtls_md_init(&md_ctx); |
| 176 | ok = md != nullptr && mbedtls_md_setup(&md_ctx, md, 1 /* HMAC */) == 0 && |
| 177 | mbedtls_pkcs5_pbkdf2_hmac(&md_ctx, (const unsigned char*)passphrase, strlen(passphrase), salt, kSaltSize, iterations, |
| 178 | (uint32_t)kKeySize, material + 9 + kKeySize) == 0; |
| 179 | mbedtls_md_free(&md_ctx); |
| 180 | } |
| 181 | |
| 182 | if (ok) { |
| 183 | // HKDF's extract step: the salt is the HMAC key, the two halves are |
| 184 | // the message, and SHA-256's output is already exactly the key size. |
| 185 | const mbedtls_md_info_t* md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); |
| 186 | ok = md != nullptr && mbedtls_md_hmac(md, salt, kSaltSize, material, sizeof(material), outKey) == 0; |
| 187 | } |
| 188 | |
| 189 | mbedtls_platform_zeroize(material, sizeof(material)); |
| 190 | return ok; |
| 191 | } |
| 192 | |
| 193 | // Hands a run-scoped copy of `size` bytes to the script through an out |
| 194 | // parameter pair, then wipes the working buffer. False = out of memory. |
no test coverage detected