Skip navigation links

@ParametersAreNonnullByDefault

Package com.pkware.smartcrypt.structured

Authenticated, length preserving, and format preserving encryption suited for databases, XML/JSON documents, etc.

See: Description

Package com.pkware.smartcrypt.structured Description

Authenticated, length preserving, and format preserving encryption suited for databases, XML/JSON documents, etc.

The Smartcrypt Structured Data component is particularly useful when encrypting data stored in a structured container such as in a JSON property or a database column. The component makes it easy to work with specific types of data and offers the ability to store encryption key information with minimal cipher text size increases.

There are 3 specific encryption offerings for structured data: authenticated, length preserving, and format preserving. For most use cases, authenticated encryption is the best option; unless you have specific needs requiring other types of encryption, use authenticated.

Authenticated Encryption

Authenticated encryption uses AES-GCM. When using authenticated encryption, not only is your data encrypted, but its authenticity is validated during decryption, making it impossible for the cipher text to be tampered with undetected. The SDK takes care of correctly generating nonce values.
MetaClient metaClient = new NativeMetaClient.Builder()
         .appName("AuthenticatedEncryptionSample")
         .appVersion("9.99.9999")
         .deviceName(UUID.randomUUID().toString())
         .deviceUniqueId(UUID.randomUUID().toString())
         .platform(Platform.LINUX)
         .platformVersion("0")
         .build();
 SmartcryptKeyManagement smartcryptKeyManagement = new SmartcryptKeyManagementImpl.Builder()
         .metaClient(metaClient)
         .persistenceCallback(new InMemoryPersistenceCallback())
         .build();

 AccountManagement accountManagement = smartcryptKeyManagement.getAccountManagement();
 accountManagement.loginManagedAccount("<your username>", "<your password>");

 Smartkeys smartkeys = smartcryptKeyManagement.getSmartkeys();
 Observable<Smartkey> smartKey = smartkeys.listAll()
         .map(keys -> {
             for (Smartkey key : keys) {
                 if (key instanceof PrivateSmartkey
                         && key.canDecrypt()
                         && key.canEncrypt()) {
                     return Optional.of(key);
                 }
             }
             return Optional.<Smartkey>empty();
         })
         .filter(Optional::isPresent)
         .map(Optional::get);

 SmartcryptStructuredData smartcryptStructuredData = new SmartcryptStructuredDataImpl.Builder()
         .dataStorage(smartcryptKeyManagement.getDataStorage())
         .build();

 AuthenticatedEncryption ae = smartcryptStructuredData.newAuthenticatedEncryption(smartKey);
 EncryptionResult encrypted = ae.encrypt(utf8("Hello, world!"));

 // Be sure to save all the information returned from Encrypt
 System.out.println("Nonce in Base64: " + base64(encrypted.nonce));
 System.out.println("Key revision: " + encrypted.keyRevision);
 System.out.println("Ciphertext in Base64: " + base64(encrypted.encryptedContent));

 byte[] decrypted = ae.decrypt(encrypted.encryptedContent, encrypted.nonce, encrypted.keyRevision);
 System.out.println("Decrypted message: " + utf8(decrypted));
 

Length Preserving Encryption

Length preserving encryption produces a cipher text that has the same number of bytes as the input text. This is useful if you do not have control over the size of the cipher text storage container such as the size of the database column. However, there are risks to using length preserving encryption.

Format Preserving Encryption

Format preserving encryption produces cipher text in the same format as the plain text. For example, if encrypting credit card numbers, the cipher text for each encryption will still be in the format of a valid credit card number. For some input types such as credit cards and social security numbers, the cipher text will still pass relevant checksum tests such as the Luhn check.

Format preserving encryption is useful if you do not have control over the size of the cipher text storage container such as the size of the database column. However, there are risks to using length preserving encryption.

MetaClient metaClient = new NativeMetaClient.Builder()
         .appName("FormatPreservingEncryptionSample")
         .appVersion("1.0.0")
         .deviceName(UUID.randomUUID().toString())
         .deviceUniqueId(UUID.randomUUID().toString())
         .platform(Platform.LINUX)
         .platformVersion("0")
         .build();
 SmartcryptKeyManagement smartcryptKeyManagement = new SmartcryptKeyManagementImpl.Builder()
         .metaClient(metaClient)
         .persistenceCallback(new InMemoryPersistenceCallback())
         .build();

 AccountManagement accountManagement = smartcryptKeyManagement.getAccountManagement();
 accountManagement.loginManagedAccount("<your username>", "<your password>");

 Smartkeys smartkeys = smartcryptKeyManagement.getSmartkeys();
 Observable<Smartkey> smartkey = smartkeys.listAll()
         .map(keys -> {
             for (Smartkey key : keys) {
                 if (key.getFeatures().stream().anyMatch(feature -> Feature.NAME_NON_ROTATABLE.equals(feature.getName()))
                         && key.canDecrypt()
                         && key.canEncrypt()) {
                     return Optional.of(key);
                 }
             }
             return Optional.<Smartkey>empty();
         })
         .filter(Optional::isPresent)
         .map(Optional::get);

 SmartcryptStructuredData smartcryptStructuredData = new SmartcryptStructuredDataImpl.Builder()
         .dataStorage(smartcryptKeyManagement.getDataStorage())
         .license("<your license key here>")
         .build();

 FormatPreservingEncryption fpe = smartcryptStructuredData.newFormatPreservingEncryption(smartkey);
 String encrypted1 = fpe.encryptAlphanumeric("Hello, world!", "1");
 String encrypted2 = fpe.encryptAlphanumeric("Hello, world!", "1");
 String encrypted3 = fpe.encryptAlphanumeric("Hello, world!", "2");
 System.out.println("The tweak is important! Encrypted1: " + encrypted1 + ", Encrypted2: " + encrypted2 + ", Encrypted3: " + encrypted3);

 String decrypted1 = fpe.decryptAlphanumeric(encrypted1, "1");
 String decrypted2 = fpe.decryptAlphanumeric(encrypted2, "2");
 String decrypted3 = fpe.decryptAlphanumeric(encrypted3, "2");
 System.out.println("The tweak is important! Decrypted1: " + decrypted1 + ", Decrypted2: " + decrypted2 + ", Decrypted3: " + decrypted3);
 
Skip navigation links
Copyright 2012-2019, PKWARE, Inc.