---
title: "Gerar uma chave e um arquivo PKCS #12 - PKI Express"
description: "Como gerar um par de chaves RSA e um CSR com o PKI Express (KeyGenerator, gen-key) e juntar a chave ao certificado emitido num arquivo PKCS #12 (.pfx) (Pkcs12Generator, create-pfx), em PHP, Java, Node.js e Python."
canonical: "https://docs.lacunasoftware.com/articles/pki-express/key-generation"
locale: "pt-BR"
product: "PKI Express"
last_updated: "2026-10-19"
---

# Gerar uma chave e um arquivo PKCS #12 - PKI Express

O [PKI Express](https://docs.lacunasoftware.com/articles/pki-express) pode gerar um par de chaves RSA no seu servidor, com uma requisição de assinatura de certificado (CSR) para
ele, e, depois que uma AC emitir o certificado, juntar a chave e o certificado num arquivo PKCS #12 (`.pfx`) com o qual você pode
[assinar](https://docs.lacunasoftware.com/articles/pki-express/pades-signature#assinar-com-uma-chave-no-servidor). Duas classes fazem isso: `KeyGenerator`, que executa o comando
`gen-key`, e `Pkcs12Generator`, que executa o `create-pfx`. 

* Os dois comandos exigem o PKI Express 1.11.0 ou posterior. As bibliotecas cliente pedem essa versão; com um PKI Express mais antigo, a
  operação falha com uma dica que informa a versão (veja [Códigos de retorno](https://docs.lacunasoftware.com/articles/pki-express/return-codes#códigos-de-retorno-nas-bibliotecas-cliente)). 
* As bibliotecas de Java, Node.js, PHP e Python têm essas classes; a de Ruby (`pki_express` 1.3.2) não tem. 
* Os [samples do PKI Suite](https://github.com/LacunaSoftware/PkiSuiteSamples) as usam para emitir um certificado com o
  [Amplia](https://docs.lacunasoftware.com/articles/amplia/integration/issue-from-csr) e depois assinar um PDF com ele (*Issue a certificate with the key on the server* e
  *Sign a PDF with a server key*). 

## Fluxo

1. `KeyGenerator.generate()`, com `genCsr` definido, devolve a chave privada e um CSR.
1. Guarde a chave no seu servidor e envie o CSR à sua AC, como o Amplia, que devolve o certificado.
1. `Pkcs12Generator.generate()` recebe a chave e o arquivo do certificado e devolve o arquivo PKCS #12, protegido pela senha que você
   informar.

Em PHP, com o pacote `lacuna/pki-express` (1.17.0): 

```php
use Lacuna\PkiExpress\KeyGenerator;
use Lacuna\PkiExpress\KeyFormats;
use Lacuna\PkiExpress\Pkcs12Generator;
use Lacuna\PkiExpress\SupportedKeySizes;

// 1. Make the key pair and the CSR.
$keyGenerator = new KeyGenerator();
$keyGenerator->keySize = SupportedKeySizes::S2048;
$keyGenerator->keyFormat = KeyFormats::JSON;
$keyGenerator->genCsr = true;
$genKey = $keyGenerator->generate();
// $genKey->key: the private key, as a string in the chosen format
// $genKey->csr: the PKCS #10 CSR, PEM-encoded

// 2. Store $genKey->key (encrypted) and send $genKey->csr to the CA,
//    which returns the certificate, saved here as $certPath.

// 3. Make the PKCS #12 file.
$pkcs12Generator = new Pkcs12Generator();
$pkcs12Generator->key = $genKey->key;
$pkcs12Generator->setCertFile($certPath);
$result = $pkcs12Generator->generate($password);
$result->pfx->writeToFile('/path/to/signer.pfx'); // or getContentRaw(), getContentBase64()
```

Os samples chamam `Util::setPkiDefaults()` nos dois objetos, como em todo operador do PKI Express, e guardam a chave e o certificado
entre os passos 1 e 3. 
Eles alertam que a chave privada deve ser criptografada antes de ser guardada. 

## Opções da geração de chave

| Opção | PHP | Valores | Padrão |
|---|---|---|---|
| Tamanho da chave, em bits | `keySize` | `SupportedKeySizes::S1024`, `S2048`, `S4096` (1024, 2048, 4096) | 2048 |
| Formato da chave | `keyFormat`, ou o argumento de `generate()` | `KeyFormats::JSON` (`json`), `KeyFormats::BLOB` (`blob`), `KeyFormats::XML` (`xml`) | `json` |
| CSR | `genCsr` | `true` para gerar um CSR; deixe sem valor para gerar só a chave | sem CSR |

* A chave é RSA. Só 1024, 2048 e 4096 bits são aceitos: as bibliotecas cliente recusam outro tamanho antes de executar o PKI Express (o
  PHP lança uma `RuntimeException`), e o próprio PKI Express devolve `36 - KeySizeNotSupported`. 
* Os três formatos guardam a mesma chave privada, serializada de formas diferentes: `json` é um objeto JSON com os parâmetros RSA, `xml`
  um documento `<RSAKeyValue>` e `blob` um blob de chave CSP em Base64. Os samples usam `json`. 
* O CSR é uma requisição PKCS #10, codificada em PEM e assinada com SHA-256 com RSA; ele leva só a chave pública, e por isso o subject do
  certificado vem da AC (no Amplia, do pedido). 
* `generate()` devolve um `KeyGenerationResult` com duas strings: `key` e `csr` (`null` sem `genCsr`). 

## Opções do PKCS #12

| Entrada | PHP |
|---|---|
| A chave, como o `KeyGenerator` a devolveu, em qualquer dos três formatos | propriedade `key` (ou o primeiro argumento do construtor) |
| O arquivo do certificado | `setCertFile($path)` (alias de `setCertFileFromPath`), `setCertFileFromContentRaw($bytes)`, `setCertFileFromContentBase64($base64)` |
| A senha do arquivo PKCS #12 | argumento de `generate($password)`, ou a propriedade `password` |

* O PKI Express reconhece o formato da chave pelo conteúdo; uma chave que ele não consegue ler dá `37 - BadKeyFormat` ou `38 - BadKey`. 
* Sem senha, o arquivo PKCS #12 é criado com uma senha vazia. 
* `generate()` devolve um `Pkcs12GenerationResult` cujo `pfx` é um `Pkcs12Certificate`: `getContentRaw()` dá os bytes,
  `getContentBase64()` o Base64, e `writeToFile($path)` grava o arquivo. Para assinar com ele, passe os bytes a `setPkcs12Content()` e a
  senha a `setCertPassword()`, como faz o sample de assinatura PAdES com chave no servidor. 
* A biblioteca cliente passa a chave e a senha ao `pkie` como argumentos de linha de comando. 
* Se você preferir que a AC gere a chave, o Amplia pode devolver o próprio arquivo PKCS #12: veja [Emitir um arquivo PKCS #12](https://docs.lacunasoftware.com/articles/amplia/integration/pkcs12).

## Em cada linguagem

As classes têm o mesmo nome em todas as bibliotecas que as têm; os setters e os objetos de resultado mudam: 

| Biblioteca | Opções da chave | Resultado da chave | Certificado e senha | Resultado do PKCS #12 |
|---|---|---|---|---|
| PHP | `keySize`, `keyFormat`, `genCsr` | `$r->key`, `$r->csr` | `key`, `setCertFile($path)`, `generate($password)` | `$r->pfx->getContentRaw()`, `writeToFile($path)` |
| Java | `setKeySize(int)`, `setKeyFormat(KeyFormats)`, `setGenCsr(boolean)` | `getKey()`, `getCsr()` | `setKey`, `setCertFile(path)` (também `byte[]`, `InputStream`), `generate(password)` | `getPfxContent()` (`byte[]`), `getPfxContentBase64()` |
| Node.js | construtor `{ keySize, keyFormat, genCsr }`, ou os setters | `key`, `csr` | construtor `{ key }`, `setCertFileFromPathSync(path)`, `generate(password)` | `pfx.contentRaw` (`Buffer`), `pfx.contentBase64`, `pfx.writeToFileSync(path)` |
| Python | `key_size`, `key_format`, `gen_csr` | `key`, `csr` | `key`, `set_cert_file_from_path(path)`, `generate(password)` | `pfx.content` (`bytes`), `pfx.write_to_file(path)` |

* Java, Node.js e Python usam por padrão uma chave de 2048 bits no formato `json`; o PHP não envia nenhuma opção, e o PKI Express aplica
  os mesmos padrões. 
* Em Python, defina `key_size` com as constantes de `SupportedKeySizes`, que são strings (`'2048'`); em Node.js, `keySize` aceita `2048`
  ou `'2048'`. 
* Todas as bibliotecas exportam `KeyFormats`; `SupportedKeySizes`, só PHP e Python. 
* Em Node.js, `generate()` devolve uma promise. 

**Java**

```java
KeyGenerator keyGenerator = new KeyGenerator();
keyGenerator.setKeySize(2048);
keyGenerator.setKeyFormat(KeyFormats.JSON);
keyGenerator.setGenCsr(true);
KeyGenerationResult genKey = keyGenerator.generate();
// genKey.getKey(), genKey.getCsr()

Pkcs12Generator pkcs12Generator = new Pkcs12Generator();
pkcs12Generator.setKey(keyJson); // the key from genKey.getKey(), read back from storage
pkcs12Generator.setCertFile(certPath);
Pkcs12GenerationResult pkcs12GenResult = pkcs12Generator.generate(password);
signer.setPkcs12(pkcs12GenResult.getPfxContent());
signer.setCertPassword(password);
```

**Node.js**

```js
const { KeyGenerator, KeyFormats, Pkcs12Generator } = require('pki-express');

const keyGenerator = new KeyGenerator({ keySize: 2048, keyFormat: KeyFormats.JSON, genCsr: true });
const genKey = await keyGenerator.generate();
// genKey.key, genKey.csr

const pkcs12Generator = new Pkcs12Generator({ key: keyJson }); // the key from genKey.key, read back from storage
pkcs12Generator.setCertFileFromPathSync(certPath);
const pkcs12GenResult = await pkcs12Generator.generate(password);
await signer.setPkcs12FromRaw(pkcs12GenResult.pfx.contentRaw);
signer.certPassword = password;
```

**Python**

```python
from pkiexpress import KeyGenerator, Pkcs12Generator, SupportedKeySizes

key_generator = KeyGenerator()
key_generator.key_size = SupportedKeySizes.S2048
key_generator.gen_csr = True
gen_key = key_generator.generate()
# gen_key.key, gen_key.csr

pkcs12_generator = Pkcs12Generator()
pkcs12_generator.key = gen_key.key
pkcs12_generator.set_cert_file_from_base64(cert.content_base64)
pkcs12_gen_result = pkcs12_generator.generate('1234')
pkcs12_gen_result.pfx.write_to_file('signer.pfx')
```

## Erros

Um comando que falha dá um dos [códigos de retorno](https://docs.lacunasoftware.com/articles/pki-express/return-codes) do PKI Express: `36 - KeySizeNotSupported`, `37 - BadKeyFormat` ou
`38 - BadKey` nesses comandos, e `04 - BadCertificate` quando não é possível decodificar o arquivo do certificado. Em PHP, trate a
`CommandException` e leia `$e->returnCode`: veja [Códigos de retorno nas bibliotecas cliente](https://docs.lacunasoftware.com/articles/pki-express/return-codes#códigos-de-retorno-nas-bibliotecas-cliente). 

TODO(docs): se o `create-pfx` verifica se o certificado corresponde à chave, e qual código de retorno ele dá quando não corresponde.

## Veja também

* [Assinar um PDF com uma chave no servidor](https://docs.lacunasoftware.com/articles/pki-express/pades-signature#assinar-com-uma-chave-no-servidor)
* [Emitir a partir de um CSR](https://docs.lacunasoftware.com/articles/amplia/integration/issue-from-csr) com o Amplia
* [Referência rápida do PKI Express](https://docs.lacunasoftware.com/articles/pki-express/quick-reference)
