Partager via


Déchiffrer les instantanés exportés à partir de Recall

Ce guide montre aux développeurs comment déchiffrer les instantanés exportés Recall à utiliser dans les applications. Vous découvrirez le processus de déchiffrement complet avec des exemples de code de travail que vous pouvez implémenter immédiatement.

L’exportation de Recall captures instantanées n’est prise en charge que sur les appareils de l’Espace économique européen (EEE). L’exportation de Recall captures instantanées est un processus initié par l’utilisateur et est par utilisateur. Les instantanés exportés sont chiffrés.

Apprenez-en davantage sur l’exportation Recall d’instantanés ou consultez la vue d’ensemble pour plus d’informations sur leRecall fonctionnement de cette fonctionnalité soutenue par l’IA.

Prerequisites

L’option d’exportation Recall de captures instantanées est disponible uniquement sur les appareils Copilot+ PC dans l’Espace économique européen (EEE) qui exécutent la dernière version préliminaire du programme Windows Insider.

Avant de commencer, vous aurez besoin des éléments suivants :

  • Instantanés exportés : l’utilisateur doit d’abord exporter Recall des instantanés et fournir le chemin d’accès au dossier où il est enregistré.
  • Code d’exportation : code d’exportation de 32 caractères Recall fourni lors de l’exportation d’instantanés.
  • Dossier de sortie : chemin d’accès au dossier de destination où les fichiers de .jpg et d'.json déchiffrés associés aux instantanés exportés sont enregistrés.

Comment déchiffrer les instantanés exportés Recall

Commencez avec du code d'exemple pour le déchiffrement des captures instantanées exportées Recall dans le référentiel GitHub RecallSnapshotsExport. Suivez le processus pas à pas ci-dessous pour comprendre le fonctionnement du déchiffrement.

Clé d'export d'ordinateur

L’utilisateur doit fournir l’emplacement (chemin d’accès du dossier) où ses instantanés exportés Recall ont été enregistrés, en plus du Recall code d’exportation qu’il a été invité à enregistrer pendant la configuration initiale Recall . Le Recall code d’exportation ressemble à ceci : 0a0a-0a0a-1111-bbbb-2222-3c3c-3c3c-3c3c

Tout d’abord, supprimez le tiret pour obtenir une chaîne de 32 caractères : 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;
}

Voir l’exemple de code

Ensuite, générez un tableau contenant la valeur d’octet pour chaque paire de chiffres hexadécimaux à son tour.

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;
}

Voir l’exemple de code

Ensuite, prenez ce tableau et calculez le hachage SHA256, ce qui entraîne une valeur de 32 octets, qui est la clé d’exportation. À présent, n’importe quel nombre d’instantanés peut être déchiffré à l’aide de la clé d’exportation résultante.

    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));

Consultez l’exemple de code.

Déchiffrer les instantanés chiffrés

Agencement d’un instantané (au format little-endian) : | uint32_t version | uint32_t encryptedKeySize | uint32_t encryptedContentSize | uint32_t contentType | uint8_t[KeySIze] encryptedContentKey | uint8_t[ContentSize] encryptedContent |

Tout d’abord, lisez les quatre valeurs de 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();

Consultez l’exemple de code.

Ensuite, vérifiez que la version a la valeur 2.

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

Consultez l’exemple de code.

Ensuite, lisez le contenu de la clé chiffrée.

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

Consultez l’exemple de code.

Déchiffrer le contenu de la clé chiffrée

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;
}

Consultez l’exemple de code.

utilisation de l’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));

Voir l’exemple de code

Pour obtenir contentKey (algorithme de chiffrement est AES_GCM)

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

Consultez l’exemple de code.

Lire le contenu chiffré

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

Consultez l’exemple de code.

Déchiffrer le encryptedContent

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;
}

Consultez l’exemple de code.

avec contentKey (algorithme de chiffrement est AES_GCM)

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

Consultez l’exemple de code.

Contenu d’instantané déchiffré Recall à exporter sous forme d’une image .jpg avec des métadonnées .json correspondantes dans le dossier désigné au chemin d'accès spécifié.

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

Consultez l’exemple de code.

La sortie attendue inclut les éléments suivants :

  • Captures instantanées déchiffrées enregistrées en tant que fichiers .jpg.
  • Métadonnées correspondantes enregistrées en tant que fichiers .json.

Les deux types de fichiers partagent le même nom de fichier et se trouvent dans le dossier de sortie spécifié.

En savoir plus sur Recall