Reputation: 11
I want to reverse this encryption procedure in order to decrypt a sealed secret.
this is taken from the bitnami documentation.
The secret is encrypted by AES-256-GCM with a randomly-generated single-use 32 byte session key.
The result of this operation will be called AES encrypted data
in the next diagram, and the present step is the 1.
.
The session key used by AES-256-GCM to encrypt the Secret is encapsulated with the controller's public key using RSA-OAEP with SHA256.
The OAEP input content, called label
in the next diagram, differs depending on the sealed secret controller scope configuration. This algorithm is only used to encrypt the AES session key.
Default scope configuration : label
is equal to the concatenation of the Secret's namespace and the Secret's name.
Namespace-wide scope configuration : label
is equal to the Secret's namespace.
Cluster-wide scope configuration : label
is empty.
The result of the RSA-OAEP encryption is called RSA encrypted data
in the next diagram, and the present step is the 2.
.
The final Sealed Secret data format is the following (where ||
is the concatenation operator): size of AES encrypted key (2 bytes) || RSA encrypted data || AES encrypted data
Secret
|
│
K_s────────────►│
│ │
K_pub───────►│ │
│ │ 1.
label───────►│ 2. │
│ │
┌──────────────────────┬───────▼───────┬──────▼───────┐
Sealed Secret data = │size of AES encrypted │ RSA encrypted │ AES encrypted│
│key (2 bytes) │ data │ data │
└──────────────────────┴───────────────┴──────────────┘
K_s = 256 bits single-use session key, used by AES-GCM
K_pub = Public key from the self-signed certificate, used by RSA-OAEP
label = Additional input for RSA-OAEP encryption.
Content differs depending on the scope configuration:
* Default config : label = Secret's namespace || Secret's name
* Namespace-wide : label = Secret's namespace
* Cluster-wide : label is empty
The decryption is simply the inversion of the encryption.
Size of AES encrypted key
is read and used to separate RSA encrypted data
and AES encrypted data
properly.
Then the private key associated with the public key (see Session key encryption) is used with the label
to decrypt the RSA encrypted data
, effectively retrieving the AES session key.
To end this process, the AES encrypted data
is decrypted using the AES session key, therefore unsealing the original Secret.
this is what i have done till now, but i am stuck:
import * as fs from 'fs';
import * as forge from 'node-forge';
// Load the private key from my local files
const privateKeyPEM = fs.readFileSync('priv.key', 'utf8');
const privateKey = forge.pki.privateKeyFromPem(privateKeyPEM);
// Sealed Secret data
const sealedSecretData = Buffer.from(
'AgAdMSMYznQfAavqvsmqVnjnZYnaPHyrLoxsj6Qg5uoH0yWgkgea9ipMgl2CAXaatUxsz4Qx3ULM6GyRmOvTP47ETt0h3rALxK47lXdoDq3z9937/2rln2uMaGhCyyTQ0m7G3F0Rj3J5NRFnuuVhYZit/v6vrXHKqAHTuG0AxIA/nuN0o3nFN7+MmBs3RTXPII+6CYYmho3ldZwimyQKrBkbbZpRjFnmvv2ErGFQg9lz63QxzTqE5EPvrz0DIwGFUxJKKZ2fOucVcXavEkZJUflKFnK58d/ur90GPQp/N5Ivmqj+1Lf7L5ezqAP5WpmK0M2q69D6RG+OUoOgpYLNQJybL4nxqgv4lFu0eXHxBwqjmNUOqkFDAd5APS1CDaFNjcw5dJ009jqeUN+4AxM2WtfzjjQz6rf5M5UmGMDCc26mjx3fOvi8AAIvEJ6B/hJcRwnC0zqsK0apJ00VykRyHsOTK8G6/eFy8wFnvx4neBCNKgQAMMq0F8A5ekWVZg7sxdeUucc2KXHc53c/p+tOcf0eMBCwefM7ijcoc85x+0wr+wigJ71BakjCGZfQDlnnfOGf9ayp4EhpiPfUdNQ8k1A3G45dE8wJdrUtvn4Qoootevhb9acWM3rKjFstDj3FB8epCct85Fnu5y8QGqWPfUTiprSNWAc+1zejXtZULSWal2cf66kniG+hjjAeEU8l2unncQj+0mf/',
'base64'
);
// Parse the Sealed Secret data
const aesKeySize = sealedSecretData.readUIntBE(0,2);
const rsaEncryptedData = sealedSecretData.slice(2, 2 + aesKeySize);
const aesEncryptedData = sealedSecretData.slice(2 + aesKeySize , sealedSecretData.length - 1);
// the label as specified in the docs above
const label = Buffer.from('kube-systemsealed-secrets-keyfc5ht', 'utf8');
// Decrypt RSA encrypted data to get the AES session key
const rsaEncryptedBuffer = forge.util.createBuffer(rsaEncryptedData.toString('binary'));
const rsaDecryptedBytes = privateKey.decrypt(rsaEncryptedBuffer.getBytes(), 'RSA-OAEP', {
md: forge.md.sha256.create(),
label,
});
const aesSessionKey = forge.util.createBuffer(rsaDecryptedBytes).getBytes();
// Decrypt AES encrypted data
const aesDecipher = forge.cipher.createDecipher('AES-GCM', forge.util.hexToBytes(aesSessionKey));
aesDecipher.start({ iv: aesEncryptedData.slice(0, 16) });
aesDecipher.update(forge.util.createBuffer(aesEncryptedData.slice(16)));
aesDecipher.finish();
const decryptedSecretData = aesDecipher.output.getBytes();
console.log(decryptedSecretData);
i get an error as follows: Error: Invalid RSAES-OAEP padding.
Upvotes: 0
Views: 144