You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Intel SGX开发:如何获取Enclave内sgx_ecc256_create_key_pair生成的公钥?

Exporting ECC Public Key from Intel SGX Enclave & Setting Up Encryption/Decryption Flow

Hey there! As someone who's worked with Intel SGX ECC operations, let me break down exactly how to export your generated public key and build the encryption/decryption workflow you need. Let's start with the core steps:

1. Understand the SGX ECC Public Key Structure

The sgx_ecc256_create_key_pair function generates keys of type sgx_ec256_private_t (private key) and sgx_ec256_public_t (public key). The public key struct contains two 32-byte arrays: x and y (the affine coordinates of the elliptic curve point). To export this to the untrusted app, you'll need to use an ECALL (since enclaves can't write directly to external memory).

2. Define the ECALL in Your EDL File

First, update your Enclave Definition Language (.edl) file to expose functions for generating/exporting the public key and decrypting data inside the enclave. Important: Never expose the private key outside the enclave—keep it stored securely inside the enclave's memory.

enclave {
    trusted {
        // Generate key pair and export ONLY the public key
        public sgx_status_t ecc_generate_export_pubkey(sgx_ec256_public_t* out_public_key);
        
        // Decrypt externally encrypted data using the enclave-held private key
        public sgx_status_t ecc_decrypt_data(
            const uint8_t* encrypted_data,
            size_t encrypted_len,
            uint8_t* decrypted_data,
            size_t* out_decrypted_len
        );
    };
};

3. Implement the Trusted ECALL Functions in the Enclave

Inside your enclave code, store the private key in a static variable (so it stays in secure memory) and implement the ECALLs:

#include "sgx_ecc.h"
#include "sgx_tcrypto.h"

// Store private key securely inside the enclave (never expose this!)
static sgx_ec256_private_t g_enclave_private_key;

sgx_status_t ecc_generate_export_pubkey(sgx_ec256_public_t* out_public_key) {
    if (!out_public_key) {
        return SGX_ERROR_INVALID_PARAMETER;
    }

    // Generate key pair: private key stays in g_enclave_private_key, public key is passed out
    return sgx_ecc256_create_key_pair(&g_enclave_private_key, out_public_key);
}

sgx_status_t ecc_decrypt_data(
    const uint8_t* encrypted_data,
    size_t encrypted_len,
    uint8_t* decrypted_data,
    size_t* out_decrypted_len
) {
    if (!encrypted_data || !decrypted_data || !out_decrypted_len) {
        return SGX_ERROR_INVALID_PARAMETER;
    }

    // Assume encrypted data follows this format (match your external encryption logic):
    // [32-byte ephemeral pubkey x][32-byte ephemeral pubkey y][12-byte IV][ciphertext][16-byte GCM tag]
    if (encrypted_len < 32 + 32 + 12 + 16) {
        return SGX_ERROR_INVALID_PARAMETER;
    }

    // Parse ephemeral public key (used for ECDH key exchange)
    sgx_ec256_public_t ephemeral_pubkey;
    memcpy(ephemeral_pubkey.x, encrypted_data, 32);
    memcpy(ephemeral_pubkey.y, encrypted_data + 32, 32);
    const uint8_t* iv = encrypted_data + 64;
    const uint8_t* ciphertext = encrypted_data + 64 + 12;
    size_t ciphertext_len = encrypted_len - 64 - 12 - 16;
    const uint8_t* tag = encrypted_data + encrypted_len - 16;

    // Compute shared secret via ECDH (enclave private key + ephemeral public key)
    sgx_ec256_dh_shared_t shared_secret;
    sgx_status_t status = sgx_ecc256_compute_shared_dhkey(&g_enclave_private_key, &ephemeral_pubkey, &shared_secret);
    if (status != SGX_SUCCESS) return status;

    // Derive AES-GCM key from shared secret using HKDF
    uint8_t aes_key[32];
    sgx_hkdf_context_t hkdf_ctx;
    status = sgx_hkdf_init(&hkdf_ctx, SGX_HASH_SHA256, shared_secret.s, sizeof(shared_secret.s), NULL, 0);
    if (status != SGX_SUCCESS) return status;
    
    status = sgx_hkdf_extract(&hkdf_ctx, NULL, 0);
    if (status != SGX_SUCCESS) { sgx_hkdf_close(&hkdf_ctx); return status; }
    
    status = sgx_hkdf_expand(&hkdf_ctx, NULL, 0, aes_key, sizeof(aes_key));
    sgx_hkdf_close(&hkdf_ctx);
    if (status != SGX_SUCCESS) return status;

    // Decrypt with AES-GCM
    sgx_aes_gcm_128bit_key_t gcm_key;
    memcpy(gcm_key, aes_key, sizeof(gcm_key));
    sgx_aes_gcm_128bit_iv_t gcm_iv;
    memcpy(gcm_iv, iv, sizeof(gcm_iv));
    sgx_aes_gcm_128bit_tag_t gcm_tag;
    memcpy(gcm_tag, tag, sizeof(gcm_tag));

    status = sgx_rijndael128GCM_decrypt(
        &gcm_key,
        ciphertext,
        ciphertext_len,
        decrypted_data,
        &gcm_iv,
        sizeof(gcm_iv),
        NULL, 0,
        &gcm_tag
    );
    if (status != SGX_SUCCESS) return status;

    *out_decrypted_len = ciphertext_len;
    return SGX_SUCCESS;
}

4. Call the ECALL from the Untrusted Application

In your external app, call the ECALL to get the public key, then use ECIES (Elliptic Curve Integrated Encryption Scheme) to encrypt data (since ECC doesn't support direct encryption). Below is an example using OpenSSL for ECIES encryption:

#include "sgx_urts.h"
#include "your_enclave_u.h"
#include <openssl/ec.h>
#include <openssl/evp.h>
#include <stdlib.h>
#include <stdio.h>

// Convert SGX public key to OpenSSL EC_KEY structure
EC_KEY* sgx_pubkey_to_openssl(const sgx_ec256_public_t* sgx_pub) {
    EC_KEY* ec_key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); // Matches SGX's secp256r1 curve
    if (!ec_key) return NULL;

    EC_POINT* pub_point = EC_POINT_new(EC_KEY_get0_group(ec_key));
    if (!pub_point) { EC_KEY_free(ec_key); return NULL; }

    // Set x/y coordinates from SGX public key
    BIGNUM* x = BN_bin2bn(sgx_pub->x, 32, NULL);
    BIGNUM* y = BN_bin2bn(sgx_pub->y, 32, NULL);
    if (!x || !y || EC_POINT_set_affine_coordinates_GFp(
        EC_KEY_get0_group(ec_key), pub_point, x, y, NULL) != 1) {
        BN_free(x); BN_free(y); EC_POINT_free(pub_point); EC_KEY_free(ec_key);
        return NULL;
    }

    if (EC_KEY_set_public_key(ec_key, pub_point) != 1) {
        BN_free(x); BN_free(y); EC_POINT_free(pub_point); EC_KEY_free(ec_key);
        return NULL;
    }

    BN_free(x); BN_free(y); EC_POINT_free(pub_point);
    return ec_key;
}

// ECIES encryption using AES-256-GCM
int encrypt_data(const sgx_ec256_public_t* sgx_pub, const uint8_t* plaintext, size_t plaintext_len, uint8_t** out_encrypted, size_t* out_len) {
    EC_KEY* ec_key = sgx_pubkey_to_openssl(sgx_pub);
    if (!ec_key) return -1;

    EVP_PKEY* pkey = EVP_PKEY_new();
    if (!pkey || EVP_PKEY_assign_EC_KEY(pkey, ec_key) != 1) {
        EVP_PKEY_free(pkey); EC_KEY_free(ec_key); return -1;
    }

    EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
    uint8_t ephemeral_pub[64]; // x + y bytes
    int ephemeral_len;

    // Initialize ECIES seal (generates ephemeral key pair automatically)
    if (EVP_SealInit(ctx, EVP_aes_256_gcm(), &ephemeral_pub, &ephemeral_len, NULL, &pkey, 1) != 1) {
        EVP_CIPHER_CTX_free(ctx); EVP_PKEY_free(pkey); return -1;
    }

    // Allocate buffer for encrypted data: ephemeral pubkey + IV + ciphertext + tag
    *out_len = ephemeral_len + EVP_GCM_TLS_TAG_LEN + plaintext_len;
    *out_encrypted = malloc(*out_len);
    if (!*out_encrypted) {
        EVP_CIPHER_CTX_free(ctx); EVP_PKEY_free(pkey); return -1;
    }

    // Copy ephemeral public key to output
    memcpy(*out_encrypted, ephemeral_pub, ephemeral_len);

    // Encrypt plaintext
    int cipher_len;
    if (EVP_SealUpdate(ctx, *out_encrypted + ephemeral_len, &cipher_len, plaintext, plaintext_len) != 1) {
        free(*out_encrypted); EVP_CIPHER_CTX_free(ctx); EVP_PKEY_free(pkey); return -1;
    }

    int final_len;
    if (EVP_SealFinal(ctx, *out_encrypted + ephemeral_len + cipher_len, &final_len) != 1) {
        free(*out_encrypted); EVP_CIPHER_CTX_free(ctx); EVP_PKEY_free(pkey); return -1;
    }

    *out_len = ephemeral_len + cipher_len + final_len;

    EVP_CIPHER_CTX_free(ctx); EVP_PKEY_free(pkey);
    return 0;
}

int main() {
    sgx_enclave_id_t eid;
    sgx_status_t status = sgx_create_enclave("your_enclave.signed.so", SGX_DEBUG_FLAG, NULL, NULL, &eid, NULL);
    if (status != SGX_SUCCESS) {
        fprintf(stderr, "Failed to create enclave\n");
        return -1;
    }

    // Get public key from enclave
    sgx_ec256_public_t enclave_pubkey;
    status = ecc_generate_export_pubkey(eid, &enclave_pubkey);
    if (status != SGX_SUCCESS) {
        sgx_destroy_enclave(eid);
        fprintf(stderr, "Failed to generate/export pubkey\n");
        return -1;
    }

    // Encrypt sample data
    const uint8_t plaintext[] = "Secret message for SGX enclave!";
    size_t plaintext_len = sizeof(plaintext) - 1;
    uint8_t* encrypted_data;
    size_t encrypted_len;

    if (encrypt_data(&enclave_pubkey, plaintext, plaintext_len, &encrypted_data, &encrypted_len) != 0) {
        sgx_destroy_enclave(eid);
        fprintf(stderr, "Encryption failed\n");
        return -1;
    }

    // Decrypt inside enclave
    uint8_t decrypted_data[256];
    size_t decrypted_len = sizeof(decrypted_data);
    status = ecc_decrypt_data(eid, encrypted_data, encrypted_len, decrypted_data, &decrypted_len);
    if (status != SGX_SUCCESS) {
        free(encrypted_data);
        sgx_destroy_enclave(eid);
        fprintf(stderr, "Decryption failed\n");
        return -1;
    }

    printf("Decrypted message: %.*s\n", (int)decrypted_len, decrypted_data);

    free(encrypted_data);
    sgx_destroy_enclave(eid);
    return 0;
}

Key Notes to Remember

  • Never expose the private key: Keeping it inside the enclave ensures it's never exposed to untrusted memory.
  • ECIES is mandatory: ECC is designed for key exchange/signatures, not direct encryption. ECIES combines ECDH (for shared secret) with symmetric encryption (like AES-GCM) to secure data.
  • Match encryption/decryption formats: Ensure the structure of encrypted data (ephemeral key, IV, ciphertext, tag) is identical between the external app and enclave.

内容的提问来源于stack exchange,提问作者ramzi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 09:24:08