Condividi tramite


Decrittografare gli snapshot esportati da Recall

Questa guida illustra agli sviluppatori come decrittografare gli snapshot esportati Recall da usare nelle applicazioni. Si apprenderà il processo di decrittografia completo con esempi di codice funzionanti che è possibile implementare immediatamente.

L'esportazione Recall di snapshot è supportata solo nei dispositivi nell'Area economica europea (SEE). L'esportazione degli Recall snapshot è un processo avviato dall'utente e applicato individualmente a ciascun utente. Gli snapshot esportati vengono crittografati.

Altre informazioni su come esportare Recall gli snapshot o vedere la Recall panoramica per altre informazioni sul funzionamento di questa funzionalità supportata dall'intelligenza artificiale.

Prerequisiti

L'opzione per esportare Recall gli snapshot è disponibile solo nei dispositivi Copilot+ PC nell'Area economica europea (SEE) che eseguono la build di anteprima più recente del Programma Windows Insider.

Prima di iniziare, è necessario:

  • Snapshot esportati: l'utente deve prima esportare Recall gli snapshot e specificare il percorso della cartella in cui vengono salvati.
  • Codice di esportazione: codice di esportazione di 32 caratteri Recall fornito durante l'esportazione di snapshot.
  • Cartella di output: verrà salvato il percorso della cartella di destinazione in cui verranno salvati i file .jpg decrittografati e .json associati agli snapshot esportati.

Come decrittografare gli snapshot esportati Recall

Inizia con il codice di esempio per decrittografare gli snapshot esportati Recall nel repository GitHub RecallSnapshotsExport. Seguire il processo dettagliato seguente per comprendere il funzionamento della decrittografia.

Calcolare la chiave di esportazione

L'utente dovrà specificare il percorso (percorso della cartella) in cui sono stati salvati gli snapshot esportati Recall , oltre al Recall codice di esportazione richiesto per il salvataggio durante l'installazione iniziale Recall . Il Recall codice di esportazione è simile al seguente: 0a0a-0a0a-1111-bbbb-2222-3c3c-3c3c-3c3c

Rimuovere prima di tutto il trattino per ottenere una stringa di 32 caratteri: 0a0a0a0a1111bbbb22223c3c3c3c3c3c

std::wstring UnexpandExportCode(std::wstring code)
{
    if (code.size() > 32)
    {
        code.erase(std::remove(code.begin(), code.end(), ' '), code.end()); // Remove spaces
        code.erase(std::remove(code.begin(), code.end(), '-'), code.end()); // Remove hyphens
    }


    if (code.size() != 32)
    {
        std::wcout << L"The export code has incorrect number of characters."<< std::endl;
    }


    return code;
}

Vedere il codice di esempio

Successivamente, compilare una matrice contenente il valore di byte per ogni coppia di cifre esadecimale a sua volta.

std::vector<uint8_t> HexStringToBytes(const std::wstring& hexString)
{
    std::vector<uint8_t> bytes;
    if (hexString.length() % 2 != 0)
    {
        throw std::invalid_argument("Hex string must have an even length");
    }


    for (size_t i = 0; i < hexString.length(); i += 2)
    {
        std::wstring byteString = hexString.substr(i, 2);
        uint8_t byte = static_cast<uint8_t>(std::stoi(byteString, nullptr, 16));
        bytes.push_back(byte);
    }


    return bytes;
}

Vedere il codice di esempio

Quindi, prendere tale matrice e calcolare l'hash SHA256, che restituisce un valore a 32 byte, ovvero la chiave di esportazione. È ora possibile decrittografare qualsiasi numero di snapshot usando la chiave di esportazione risultante.

    std::vector<uint8_t> exportKeyBytes(c_keySizeInBytes);
    THROW_IF_NTSTATUS_FAILED(BCryptHash(
        BCRYPT_SHA256_ALG_HANDLE,
        nullptr,
        0,
        exportCodeBytes.data(),
        static_cast<ULONG>(exportCodeBytes.size()),
        exportKeyBytes.data(),
        c_keySizeInBytes));

Vedere il codice di esempio.

Decrittografare gli snapshot crittografati

Struttura di uno snapshot (in formato little-endian): | uint32_t version | uint32_t encryptedKeySize | uint32_t encryptedContentSize | uint32_t contentType | uint8_t[KeySIze] encryptedContentKey | uint8_t[ContentSize] encryptedContent |

Prima di tutto, leggere i quattro valori uint32_t.

    EncryptedSnapshotHeader header{};
    reader.ByteOrder(winrt::ByteOrder::LittleEndian);


    header.Version = reader.ReadUInt32();
    header.KeySize = reader.ReadUInt32();
    header.ContentSize = reader.ReadUInt32();
    header.ContentType = reader.ReadUInt32();

Vedere il codice di esempio.

Verificare quindi che la versione abbia il valore 2.

    if (header.Version != 2)
    {
        throw std::runtime_error("Insufficient data header version.");
    }

Vedere il codice di esempio.

Quindi, leggi il contenuto della chiave crittografata.

    std::vector<uint8_t> keybytes(header.KeySize);
    reader.ReadBytes(keybytes);

Vedere il codice di esempio.

Decrittografa il contenuto della chiave crittografata

wil::unique_bcrypt_key DecryptExportKey(BCRYPT_KEY_HANDLE key, std::span<uint8_t const> encryptedKey)
{
    THROW_HR_IF(E_INVALIDARG, encryptedKey.size() != c_totalSizeInBytes);


    BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO AuthInfo{};
    BCRYPT_INIT_AUTH_MODE_INFO(AuthInfo);
    AuthInfo.pbNonce = const_cast<uint8_t*>(encryptedKey.data()); 
    AuthInfo.cbNonce = c_nonceSizeInBytes;
    AuthInfo.pbTag = const_cast<uint8_t*>(encryptedKey.data() + c_nonceSizeInBytes + c_childKeySizeInBytes);
    AuthInfo.cbTag = c_tagSizeInBytes;


    uint8_t decryptedKey[c_childKeySizeInBytes] = { 0 };


    ULONG decryptedByteCount{};
    THROW_IF_FAILED(HResultFromBCryptStatus(BCryptDecrypt(
        key,
        const_cast<uint8_t*>(encryptedKey.data() + c_nonceSizeInBytes),
        c_childKeySizeInBytes,
        &AuthInfo,
        nullptr,
        0,
        decryptedKey,
        sizeof(decryptedKey),
        &decryptedByteCount,
        0)));


    wil::unique_bcrypt_key childKey;
    THROW_IF_NTSTATUS_FAILED(
        BCryptGenerateSymmetricKey(BCRYPT_AES_GCM_ALG_HANDLE, &childKey, nullptr, 0, decryptedKey, c_childKeySizeInBytes, 0));


    return childKey;
}

Vedere il codice di esempio.

uso di exportKey

    wil::unique_bcrypt_key exportKey;
    THROW_IF_NTSTATUS_FAILED(BCryptGenerateSymmetricKey(
       BCRYPT_AES_GCM_ALG_HANDLE, &exportKey, nullptr, 0, exportKeyBytes.data(), static_cast<ULONG>(exportKeyBytes.size()), 0));

Vedere il codice di esempio

Per ottenere contentKey (algoritmo di crittografia è AES_GCM)

    wil::unique_bcrypt_key contentKey = DecryptExportKey(exportKey.get(), keybytes);

Vedere il codice di esempio.

Leggi encryptedContent

    std::vector<uint8_t> contentbytes(header.ContentSize);
    reader.ReadBytes(contentbytes);

Vedere il codice di esempio.

Decrittografare il contenuto crittografato

std::vector<uint8_t> DecryptPackedData(BCRYPT_KEY_HANDLE key, std::span<uint8_t const> payload)
{
    THROW_HR_IF(E_INVALIDARG, payload.size() < c_tagSizeInBytes);
    const auto dataSize = payload.size() - c_tagSizeInBytes;
    const auto data = payload.data();


    uint8_t zeroNonce[c_nonceSizeInBytes] = { 0 };
    BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO authInfo{};
    BCRYPT_INIT_AUTH_MODE_INFO(authInfo);
    authInfo.pbNonce = zeroNonce;
    authInfo.cbNonce = c_nonceSizeInBytes;
    authInfo.pbTag = const_cast<uint8_t*>(payload.data() + dataSize);
    authInfo.cbTag = c_tagSizeInBytes;


    std::vector<uint8_t> decryptedContent(dataSize);
    ULONG decryptedSize = 0;
    const auto result = BCryptDecrypt(
        key, const_cast<uint8_t*>(data), static_cast<ULONG>(dataSize), &authInfo, nullptr, 0, decryptedContent.data(), static_cast<ULONG>(dataSize), &decryptedSize, 0);
    decryptedContent.resize(decryptedSize);


    THROW_IF_FAILED(HResultFromBCryptStatus(result));


    return decryptedContent;
}

Vedere il codice di esempio.

con contentKey (algoritmo di crittografia è AES_GCM)

    std::vector<uint8_t> decryptedContent = DecryptPackedData(contentKey.get(), contentbytes);

Vedere il codice di esempio.

Genera il contenuto dello snapshot decrittografato Recall come immagine .jpg con i metadati .json corrispondenti nel percorso della cartella designato.

void WriteSnapshotToOutputFolder(winrt::StorageFolder const& outputFolder, winrt::hstring const& fileName, winrt::IRandomAccessStream const& decryptedStream)

Vedere il codice di esempio.

L'output previsto includerà:

  • Snapshot decrittografati salvati come file di .jpg.
  • I metadati corrispondenti sono stati salvati come file .json.

Entrambi i tipi di file condividono lo stesso nome file e si trovano nella cartella di output specificata.

Scopri di più su Recall