/** Wrapper around nonVolatileWrite() which also encrypts data * using xexEncrypt(). Because this uses encryption, it is much slower * than nonVolatileWrite(). The parameters and return values are identical * to that of nonVolatileWrite(). * \param data A pointer to the data to be written. * \param partition The partition to write to. Must be one of #NVPartitions. * \param address Byte offset specifying where in the partition to * start writing to. * \param length The number of bytes to write. * \return See #NonVolatileReturnEnum for return values. * \warning Writes may be buffered; use nonVolatileFlush() to be sure that * data is actually written to non-volatile storage. */ NonVolatileReturn encryptedNonVolatileWrite(uint8_t *data, NVPartitions partition, uint32_t address, uint32_t length) { uint32_t block_start; uint32_t block_end; uint8_t block_offset; uint8_t ciphertext[16]; uint8_t plaintext[16]; uint8_t n[16]; NonVolatileReturn r; block_start = address & 0xfffffff0; block_offset = (uint8_t)(address & 0x0000000f); block_end = (address + length - 1) & 0xfffffff0; if ((address + length) < address) { // Overflow occurred. return NV_INVALID_ADDRESS; } memset(n, 0, 16); for (; block_start <= block_end; block_start += 16) { r = nonVolatileRead(ciphertext, partition, block_start, 16); if (r != NV_NO_ERROR) { return r; } writeU32LittleEndian(n, block_start); xexDecrypt(plaintext, ciphertext, n, 1); while (length && block_offset < 16) { plaintext[block_offset++] = *data++; length--; } block_offset = 0; xexEncrypt(ciphertext, plaintext, n, 1); r = nonVolatileWrite(ciphertext, partition, block_start, 16); if (r != NV_NO_ERROR) { return r; } } return NV_NO_ERROR; }
/** Wrapper around nonVolatileWrite() which also encrypts data * using xexEncrypt(). Because this uses encryption, it is much slower * than nonVolatileWrite(). The parameters and return values are identical * to that of nonVolatileWrite(). * \param data A pointer to the data to be written. * \param address Byte offset specifying where in non-volatile storage to * start writing to. * \param length The number of bytes to write. * \return See #NonVolatileReturnEnum for return values. * \warning Writes may be buffered; use nonVolatileFlush() to be sure that * data is actually written to non-volatile storage. */ NonVolatileReturn encryptedNonVolatileWrite(uint8_t *data, uint32_t address, uint8_t length) { uint32_t block_start; uint32_t block_end; uint8_t block_offset; uint8_t ciphertext[16]; uint8_t plaintext[16]; uint8_t n[16]; NonVolatileReturn r; block_start = address & 0xfffffff0; block_offset = (uint8_t)(address & 0x0000000f); block_end = (address + length - 1) & 0xfffffff0; memset(n, 0, 16); for (; block_start <= block_end; block_start += 16) { r = nonVolatileRead(ciphertext, block_start, 16); if (r != NV_NO_ERROR) { return r; } writeU32LittleEndian(n, block_start); xexDecrypt(plaintext, ciphertext, n, 1, nv_storage_tweak_key, nv_storage_encrypt_key); while (length && block_offset < 16) { plaintext[block_offset++] = *data++; length--; } block_offset = 0; xexEncrypt(ciphertext, plaintext, n, 1, nv_storage_tweak_key, nv_storage_encrypt_key); r = nonVolatileWrite(ciphertext, block_start, 16); if (r != NV_NO_ERROR) { return r; } } return NV_NO_ERROR; }