Osy#the first language built for agents
Agents firstAgentic appsWorkflowsDurable Execution — built inSecurityTestingThe editorThe UI modelOne program

Reference / Function

Crypto.Encrypt and Crypto.Decrypt

Crypto.Encrypt(plaintext) → string (ciphertext envelope) · Crypto.Decrypt(ciphertext) → string

Encrypt and decrypt values under your app's key, which the platform mints, protects, and rotates for you. There is no key parameter — you never handle key material. Ciphertext is bound to your app, so it is meaningless to anyone else, and encrypting the same value twice gives different ciphertext, so it cannot be used as a lookup key.

stable1 example compiled by CIfunctioncryptoencryptionsecurity

Summary#

Crypto.Encrypt(plaintext) returns an opaque ciphertext string; Crypto.Decrypt(ciphertext) returns the original value. Both run under your application's own encryption key, which the platform generates, protects, and rotates. You never see, choose, store, or pass a key.

Signature#

Crypto.Encrypt(<string> plaintext)  -> string   // an opaque ciphertext envelope
Crypto.Decrypt(<string> ciphertext) -> string   // the original plaintext

Description#

Use this for values that must be readable by your app but must not sit in the database in the clear — a stored third-party credential, an account number, a piece of sensitive personal data. The encryption is AES-256-GCM, which both conceals the value and authenticates it: a ciphertext that has been altered fails to decrypt rather than quietly returning corrupted data.

There is no key parameter — on purpose#

This is the most important thing about this surface. A Crypto.Encrypt(key, plaintext) form does not exist, and will not be added. The moment an app supplies its own key, that key has to live somewhere — and in practice it ends up committed in source or stored next to the data it protects, which protects nothing. So the platform owns key management entirely: it mints a key per application, keeps it encrypted at rest, and can rotate it without your app changing a line.

Two consequences follow, and both are enforced cryptographically rather than by convention:

  • Your ciphertext is yours. The application is bound into every ciphertext, so a value encrypted by your app cannot be decrypted by another — even if the ciphertext leaks, and even though the platform holds every key.
  • Rotation doesn't strand your data. Each ciphertext records which key wrote it, so values encrypted before a rotation keep decrypting afterwards.

Ciphertext is not a lookup key#

Encrypting the same value twice gives you two different ciphertexts. This is required for the encryption to be sound — reusing the randomness would let an attacker recover the key — but it has a practical consequence worth stating plainly:

You cannot find a row by encrypting a value and matching on the result. That query will never match.

If you need to look up by a sensitive value, store a hash of it alongside the ciphertext and search on the hash (see Crypto.Sha256Hex — it is deterministic, so it does work in a query). Encrypt what you need to read back; hash what you need to search by.

Crypto.Encrypt and Crypto.Decrypt run in memory and are not available inside a query.

Examples#

Store a value encrypted, and search by a hash of it:

entity PaymentMethod {
  string Ciphertext;    // the value itself — recoverable, never stored in the clear
  string Fingerprint;   // a SHA-256 hash — deterministic, so it IS searchable
}

void StoreCard(string accountNumber) {
  new PaymentMethod {
    Ciphertext = Crypto.Encrypt(accountNumber),
    Fingerprint = Crypto.Sha256Hex(accountNumber),
  };
}

// Decrypting is the only way to see the value again.
string RevealCard(PaymentMethod pm) {
  return Crypto.Decrypt(pm.Ciphertext);
}

// Look up by the HASH, never by the ciphertext — encrypting the same number again would
// produce a different envelope, so a ciphertext match would never find anything.
PaymentMethod FindCard(string accountNumber) {
  return PaymentMethod.FirstOrDefault(p => p.Fingerprint == Crypto.Sha256Hex(accountNumber));
}

See also#

Related

Crypto.Sha256Hex

SHA-256 of a string's UTF-8 bytes as 64-character lowercase hex — the secure default hash. Deterministic, so it pushes…

Crypto.HmacSha256Hex and Crypto.FixedTimeEquals

HMAC-SHA-256 authenticates a message under a shared key — proving it came from a key holder and was not altered, which…