Skip to content

Migrating from Std.Crypto to Std.OpenSSL ​

This guide explains how to transition from the deprecated Std.Crypto module functions to their replacements in Std.OpenSSL.*.

Overview of the Migration Process ​

The Std.Crypto module provided cryptographic functionality across four main areas:

  • Algorithm enumeration (Supported* functions)
  • Hashing operations
  • Symmetric encryption
  • Public key encryption (multiple variants differing by key source and passphrase type)

All cryptographic features are now unified under Std.OpenSSL.*, improving API consistency, simplifying the codebase, and enhancing OpenSSL integration.

Namespace Migration Mapping ​

The following table shows how functional areas map from old to new namespaces:

Functional AreaOld Namespace(s)New Namespace
Hash / DigestStd.Crypto.Hashing()Std.OpenSSL.Digest()
Symmetric CiphersStd.Crypto.SymmetricEncryption(), Std.Crypto.SymmEncryption()Std.OpenSSL.Ciphers()
Public Key (RSA Seal/Unseal, Sign/Verify)Multiple: PublicKeyEncryption*(), PKEncryption*() (file, LFN, buffer variants)Std.OpenSSL.PublicKey()
Algorithm EnumerationStd.Crypto.SupportedHashAlgorithms(), etc.Std.OpenSSL.Digest.AvailableAlgorithms(), Std.OpenSSL.Ciphers.AvailableAlgorithms()
Public Key Algorithm EnumerationStd.Crypto.SupportedPublicKeyAlgorithms() (deprecated)(No direct replacement yet)

Function Mapping Reference ​

The following table provides a direct mapping from deprecated functions to their replacements:

Deprecated (Std.Crypto)Replacement (Std.OpenSSL)
SupportedHashAlgorithms()Digest.AvailableAlgorithms()
SupportedSymmetricCipherAlgorithms()Ciphers.AvailableAlgorithms()
SupportedPublicKeyAlgorithms()(No direct substitute)
Hashing.Hash()Digest.Hash()
SymmetricEncryption.Encrypt() / Decrypt()Ciphers.Encrypt() / Decrypt()
SymmEncryption.Encrypt() / Decrypt()Ciphers.Encrypt() / Decrypt()
PublicKey Encrypt() variantsPublicKey.RSASeal()
PublicKey Decrypt() variantsPublicKey.RSAUnseal()
PublicKey Sign() variantsPublicKey.Sign()
PublicKey VerifySignature() variantsPublicKey.VerifySignature()

Note: The "PublicKey variants" above include:

  • PublicKeyEncryption() / PKEncryption()
  • PublicKeyEncryptionFromLFN() / PKEncryptionFromLFN()
  • PublicKeyEncryptionFromBuffer() / PKEncryptionFromBuffer()

These variants also include differences in passphrase types (VARSTRING vs DATA).

Key Conceptual Changes ​

1. Key Source Abstraction Removal ​

Previous approach: Select a module based on whether your key is in a file path, LFN, or an in-memory buffer.

New approach:

  • Public keys are always in PEM format
  • Load the key content yourself (e.g., using Std.File, dataset read, or preferably obtain from a secrets library into a STRING
  • Pass PEM content directly to Std.OpenSSL.PublicKey functions

2. Passphrase Type Normalization ​

Previous approach: Different APIs required DATA vs VARSTRING types.

New approach: Converge to the string type expected by the new API (usually STRING/VARSTRING). Convert DATA using safe encoding if it represented binary data, or treat it as raw bytes if the API permits.

3. Algorithm Specification ​

Previous approach: Implicit algorithm selection with limited control. Further, algorithms were chosen as part of the MODULE definition.

New approach: New digest/cipher functions expect an algorithm name parameter (e.g., 'SHA256', 'AES-256-CBC'). While some functions may have defaults, explicit specification is recommended for clarity and consistency.

Public Key Material Handling ​

Old DistinctionNew Practice
File path vs LFN vs Buffer modulesKeys are always in PEM format and used as STRINGs when calling new functions

Example (LFN to Buffer):

ecl
IMPORT Std;
publicKeyPEM  := GETSECRET('mykeys','mypublickeypem');
privateKeyPEM := GETSECRET('mykeys','myprivatekeypem');
sealed := Std.OpenSSL.PublicKey.RSASeal(rawData, publicKeyPEM);

Algorithm Enumeration ​

Before:

ecl
hashAlgos := Std.Crypto.SupportedHashAlgorithms();

After:

ecl
hashAlgos := Std.OpenSSL.Digest.AvailableAlgorithms();
cipherAlgos := Std.OpenSSL.Ciphers.AvailableAlgorithms();
// For public key algorithms: consult documentation or maintain a static list (e.g., ['RSA']) until an API emerges.

Performance Considerations ​

  • Hashing and symmetric operations: Should have similar performance characteristics. For large streaming operations, consider manual chunking:
ecl
// Pseudocode for chunk processing
chunks := DATASET( ... ); // each row contains chunked DATA
hashed := PROJECT(chunks, TRANSFORM(..., SELF.outHash := Std.OpenSSL.Digest.Hash(LEFT.chunk, 'SHA256')));

Testing Strategy ​

  1. Golden Test Vectors: Capture output from old implementation for representative inputs before migration
  2. Migrate code following this guide
  3. Re-run tests and verify outputs for:
    • Hash equivalence for chosen algorithms
    • Round-trip symmetric Encrypt/Decrypt operations
    • RSASeal/RSAUnseal round-trip functionality
    • Signature verification for both positive and negative test cases
  4. Compare outputs: Acceptable differences may include base64 vs raw binary representation (normalize if needed)

Common Migration Pitfalls ​

PitfallResolution
Missing algorithm parameter in new API callAlways pass explicit algorithm constant
Wrong passphrase typeEnsure STRING/VARSTRING; convert DATA appropriately
Embedded whitespace or newline differences in PEM keysTrim or normalize; ensure correct PEM header/footer remain
Assuming multi-algorithm PublicKey supportCurrently focus on RSA; extend later if library updates

Migration Checklist ​

  • [ ] Enumerate all Std.Crypto.* references in codebase
  • [ ] Classify each reference by category (hash, symmetric, public key)
  • [ ] Introduce central constants for default digest and cipher algorithms
  • [ ] Replace hashing calls and add explicit algorithm parameters
  • [ ] Replace symmetric encryption and remove module instantiation pattern
  • [ ] Refactor public key encryption: load key content, replace Encrypt/Decrypt with RSASeal/RSAUnseal, update Sign/VerifySignature calls
  • [ ] Add comprehensive tests for each transformed operation
  • [ ] Remove or quarantine legacy wrapper code

Complete Migration Example ​

Before:

ecl
IMPORT Std;
pkMod := Std.Crypto.PublicKeyEncryptionFromBuffer('RSA', pubKeyPEM, privKeyPEM, 'pw');
encPayload := pkMod.Encrypt(payload);
sig := pkMod.Sign(payload);
isOk := pkMod.VerifySignature(sig, payload);
hash := Std.Crypto.Hashing.Hash(payload);
sym := Std.Crypto.SymmetricEncryption('AES-256-CBC', 'symPass');
cipher := sym.Encrypt(payload);
plain := sym.Decrypt(cipher);

After:

ecl
IMPORT Std;

EXPORT DEFAULT_DIGEST := 'SHA256';
EXPORT DEFAULT_CIPHER := 'AES-256-CBC';

// Public key operations
encPayload := Std.OpenSSL.PublicKey.RSASeal(payload, pubKeyPEM);
sig := Std.OpenSSL.PublicKey.Sign(payload, privKeyPEM, 'pw', DEFAULT_DIGEST);
isOk := Std.OpenSSL.PublicKey.VerifySignature(sig, payload, pubKeyPEM, DEFAULT_DIGEST);

// Hash operations
hash := Std.OpenSSL.Digest.Hash(payload, DEFAULT_DIGEST);

// Symmetric encryption
cipher := Std.OpenSSL.Ciphers.Encrypt(payload, DEFAULT_CIPHER, 'symPass');
plain := Std.OpenSSL.Ciphers.Decrypt(cipher, DEFAULT_CIPHER, 'symPass');

Future-Proofing Recommendations ​

  • Centralize algorithm names to ease future migrations
  • Encapsulate OpenSSL calls in a small adapter module so future library evolution only affects one layer
  • Track HPCC Systems release notes for introduction of public key algorithm enumeration functions

Released under the Apache-2.0 License.