Freigeben über


Entschlüsseln exportierter Momentaufnahmen von Recall

Dieses Handbuch zeigt Entwicklern, wie exportierte Recall Momentaufnahmen für die Verwendung in Anwendungen entschlüsselt werden. Sie lernen den vollständigen Entschlüsselungsprozess mit funktionierenden Codebeispielen kennen, die Sie sofort implementieren können.

Das Exportieren von Recall Momentaufnahmen wird nur auf Geräten im Europäischen Wirtschaftsraum (EWR) unterstützt. Der Export von Recall-Momentaufnahmen ist ein benutzerinitiierter Prozess und individuell pro Nutzer. Exportierte Momentaufnahmen werden verschlüsselt.

Erfahren Sie mehr über das Exportieren Recall von Momentaufnahmen oder die Recall Übersicht darüber, wie dieses KI-gesicherte Feature funktioniert.

Voraussetzungen

Die Option zum Exportieren Recall von Momentaufnahmen ist nur auf Copilot+ PC-Geräten im Europäischen Wirtschaftsraum (EWR) verfügbar, die den neuesten Vorschaubuild des Windows-Insider-Programms ausführen.

Bevor Sie beginnen, benötigen Sie Folgendes:

  • Exportierte Momentaufnahmen: Der Benutzer muss zunächst Momentaufnahmen exportieren Recall und den Ordnerpfad angeben, in dem er gespeichert wird.
  • Exportcode: Der 32-stellige Recall Exportcode, der während des Snapshotexports bereitgestellt wird.
  • Ausgabeordner: Ein Zielordnerpfad, in dem die entschlüsselten .jpg und .json Dateien gespeichert werden, die den exportierten Momentaufnahmen zugeordnet sind.

Entschlüsseln exportierter Recall Momentaufnahmen

Fangen Sie mit Beispielcode zum Entschlüsseln exportierter Recall Momentaufnahmen im GitHub-Repository "RecallSnapshotsExport" an. Befolgen Sie den nachstehenden Schritt-für-Schritt-Prozess, um zu verstehen, wie die Entschlüsselung funktioniert.

Berechnung des Export-Schlüssels

Der Benutzer muss den Speicherort (Ordnerpfad) angeben, wo Ihre exportierten Recall Momentaufnahmen gespeichert wurden, zusätzlich zu dem Recall Exportcode, den Sie während der Ersteinrichtung Recall zu speichern aufgefordert wurden. Der Recall Exportcode sieht ungefähr wie folgt aus: 0a0a-0a0a-1111-bbbb-2222-3c3c-3c3c-3c3c

Entfernen Sie zuerst den Gedankenstrich, um eine 32-stellige Zeichenfolge zu erzielen: 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;
}

Siehe Beispielcode

Erstellen Sie als Nächstes ein Array, das den Bytewert für jedes Hexadezimalpaar enthält.

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

Siehe Beispielcode

Nehmen Sie dann dieses Array und berechnen Sie den SHA256-Hash, der zu einem 32-Byte-Wert führt, der den Exportschlüssel darstellt. Jetzt können mithilfe des resultierenden Exportschlüssels eine beliebige Anzahl von Momentaufnahmen entschlüsselt werden.

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

Siehe Beispielcode.

Entschlüsseln der verschlüsselten Momentaufnahmen

Das Layout einer Momentaufnahme (im Little-Endian-Format): | uint32_t version | uint32_t encryptedKeySize | uint32_t encryptedContentSize | uint32_t contentType | uint8_t[KeySIze] encryptedContentKey | uint8_t[ContentSize] encryptedContent |

Lesen Sie zunächst die vier uint32_t Werte.

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


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

Siehe Beispielcode.

Überprüfen Sie als Nächstes, ob die Version den Wert 2 aufweist.

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

Siehe Beispielcode.

Lesen Sie dann "encryptedKeyContent".

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

Siehe Beispielcode.

Entschlüsseln des verschlüsseltenKeyContent-Inhalts

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

Siehe Beispielcode.

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

Siehe Beispielcode

So erhalten Sie den contentKey (Verschlüsselungsalgorithmus ist AES_GCM)

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

Siehe Beispielcode.

Lesen von "encryptedContent"

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

Siehe Beispielcode.

Entschlüsseln des verschlüsselten Inhalts

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

Siehe Beispielcode.

mit dem Inhalts-Schlüssel (Kryptoalgorithmus ist AES_GCM)

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

Siehe Beispielcode.

Speichern Sie den entschlüsselten Inhalt der Recall-Momentaufnahme als .jpg-Bilddatei mit den entsprechenden .json-Metadaten im angegebenen Ordnerpfad.

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

Siehe Beispielcode.

Die erwartete Ausgabe enthält Folgendes:

  • Entschlüsselte Momentaufnahmen, die als .jpg Dateien gespeichert wurden.
  • Entsprechende Metadaten, die als .json Dateien gespeichert wurden.

Beide Dateitypen verwenden denselben Dateinamen und werden im angegebenen Ausgabeordner gefunden.

Weitere Informationen zu Recall