libsodium-jna is a java library that binds to libsodium C crypto APIs with Java Native Access (JNA)
Java C Shell Ruby Makefile
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.

README.md

Introduction

libsodium-jna is a java library that binds to libsodium C crypto APIs with Java Native Access (JNA). I wrote it because I did not like any of the Java implementation of libsodium. I hope you will find this project useful and fun to use.

Bug reports, suggestions are always welcome!

If you add support to more libsodium APIs, please send me a pull request. If yo do so, please do not forget to update the documentation add unit tests. If you need to generate test vectors, please look at misc/gen_test_vectors.c

Javadocs

Generated javadocs are available at: https://muquit.github.io/libsodium-jna/

Supported platforms

In theory it should work on any platform where native libsodium library works and JVM 1.7+ is available.

The implementation is tested on the following platforms with libsodium v1.0.15 with JVM 1.7 and 1.8.

Platform JVM
64 bit Windows 7 and 10 64 bit JVM
64 bit MacOS X running Sierra and El Capitan 64 bit JVM
64 bit Linux 64 bit JVM
32 bit Linux 32 bit JVM
It is reported that it works on 32 bit Windows but I personally did not test that 32 bit JVM

Requirements

  • jdk 1.7+

  • maven must be installed in order to create the jar file. However, it is possible to use the library in a non-maven project.

  • libsodium 1.0.11 or higher. libsodium-jna itself does not enforce version checking but make sure you are using libsodium v 1.0.11 or higher. Please note that the algorithm used in cryptoPwhashArgon2i() may change from version to version of libsodium, to make sure, please look at ChangeLog.

  • Make sure native libsodium is already installed in the system. This library does not come with native version of libsodium. It is a good idea to compile and install libsodium yourself instead of using one from the Internet.

  • This library does not load any libsodium library from path, rather you have to specify exactly where the library is located.

Version

The current version of libsodium-jna is 1.0.4 (updated on Dec-10-2017), works with libsodium 1.0.15

Please look at ChangeLog for what is changed in the current version.

How to use

Install native libsodium C library first

  • Compile and Install libsodium. It is a requirement.

Follow the instructions on libsodium doc page on how to compile and install. I do the following on Linux and Mac OS X:

  tar -xf libsodium-1.0.15.tar.gz
  cd libsodium-1.0.15
  ./configure
  make && make check
  sudo make install
  sudo ldconfig

Update your project's pom.xml

Add the following block inside dependencies block:

    <!--  As of v1.0.4, libsodium-jna is in the maven central. -->
    <dependency>
        <groupId>com.muquit.libsodiumjna</groupId>
        <artifactId>libsodium-jna</artifactId>
        <version>1.0.4</version>
    </dependency>

Note: If you do not use maven, look at the end of the document.

If you want to Install libsodium-jna from trunk

Trunk usually contains the latest development code.

    git clone https://github.com/muquit/libsodium-jna.git
    cd libsodium-jna
    mvn clean install
    mvn test

To load the project in Eclipse, select File->Import...->Maven->Existing Maven Projects, then Click on Next >, click on Browse... button and select the libsodium-jna directory.

Supported APIs

Before making any API calls, native sodium must be loaded from a specific path. Please look at the section Load the libsodium C Library first for details.

The following APIs are implemented at this time.

Version of sodium library

native libsodium C API java binding Description
sodium_version_string() libsodiumVersionString() Return the version of native sodium library

Generating random data

native libsodium C API java binding Description
randombytes_buf() randomBytes() Reruns specified number of unpredictable sequence of bytes

Secret-key cryptography

native libsodium C API java binding Description
crypto_secretbox_easy() public static byte[] cryptoSecretBoxEasy(byte[] message, byte[] nonce, byte[] key) Encrypts a message with a key and a nonce
crypto_secretbox_open_easy() public static byte[] cryptoSecretBoxOpenEasy(byte[] cipherText,byte[] nonce, byte[] key) Verifies and decrypts an encrypted message produced by cryptoSecretBoxEasy()
crypto_secretbox_detached() public static SodiumSecretBox cryptoSecretBoxDetached(byte[] message, byte[] nonce, byte[] key) Encrypts a message with a key and a nonce and returns authentication tag with the encrypted message
crypto_secretbox_open_detached() public static byte[] cryptoSecretBoxOpenDetached(SodiumSecretBox secretBox, byte[] nonce, byte[] key) Verifies and decrypts an encrypted message, authentication tag used in cryptoSecretBoxDetached() is needed
crypto_auth() public static byte[] cryptoAuth(byte[] message, byte[] key) Computes an authentication tag for a message
crypto_auth_verify() public static boolean cryptoAuthVerify(byte[] mac, byte[] message, byte[] key) Verifies the authentication tag for a message
crypto_secretbox_keybytes() public static NativeLong cryptoSecretBoxKeyBytes() Length of key. The API will be changed to reutrn int in next version
crypto_secretbox_noncebytes() public static NativeLong cryptoSecretBoxNonceBytes() Length of nonce. The API will be changed to reutrn int in next version
crypto_secretbox_macbytes() public static NativeLong cryptoSecretBoxMacBytes() Length of authentication code. The API will be changed to reutrn int in next version

Public-key cryptography

native libsodium C API java binding Description
crypto_box_keypair() public static SodiumKeyPair cryptoBoxKeyPair() Randomly generate a private key and a corresponding public key
crypto_scalarmult_base() public static byte[] cryptoPublicKey(byte[] privateKey) Compute public key given a private key
crypto_box_easy() public static byte[] cryptoBoxEasy(byte[] message, byte[] nonce, byte[] publicKey, byte[] privateKey) Encrypts a message with a recipient's public key, sender's private key and a nonce
crypto_box_open_easy() public static byte[] cryptoBoxOpenEasy(byte[] cipherText, byte[]nonce, byte[] publicKey, byte[] privateKey) Verifies and decrypts an encrypted message produced by cryptoBoxEasy()
crypto_box_seal() public static byte[] cryptoBoxSeal(byte[] message, byte[] recipientPublicKey) Encrypts a message for a recipient with recipient's public key
crypto_box_seal_open() public static byte[] cryptoBoxSealOpen(byte[] cipherText,byte[] pk, byte[] sk) Decrypts an encrypted message with the key pair public key and private key
crypto_box_noncebytes() public static NativeLong cryptoBoxNonceBytes() Length of nonce. The API will be changed to reutrn int in next version
crypto_box_seedbytes() public static NativeLong crytoBoxSeedBytes() Length of key seed. The API will be changed to reutrn int in next version
crypto_box_publickeybytes() public static NativeLong crytoBoxPublicKeyBytes() Length of public key. The API will be changed to reutrn int in next version
crypto_box_secretkeybytes() public static NativeLong crytoBoxSecretKeyBytes() Length of private key. The API will be changed to reutrn int in next version
crypto_box_macbytes() public static NativeLong cryptoBoxMacBytes() Length of mac. The API will be changed to reutrn int in next version
crypto_box_sealbytes() public static NativeLong cryptoBoxSealBytes() Length of seal. The API will be changed to reutrn int in next version

Password hashing, Key generation

native libsodium C API java binding Description
crypto_pwhash() public static byte[] cryptoPwhash(byte[] passwd, byte[] salt, long opsLimit, NativeLong memLimit, int algorithm) Derives a key from a password. The salt, opslimit, memlimit and algorithm can be specified.
public static byte[] cryptoPwhashArgon2i(byte[] passwd, byte[] salt) Derives a key from a password using Argon2id memory-hard function. Uses default values for opsLimit and memLimit
public static byte[] cryptoPwhashScrypt(byte[] passwd, byte[] salt) Derives a key from a password using Scrypt
crypto_pwhash_str() public static String cryptoPwhashStr(byte[] password) Derives a US ASCII encoded key from a password using memory-hard, CPU-intensive hash function
cryupto_pwhash_str_verify() public static boolean cryptoPwhashStrVerify(String usAsciiKey, byte[] password) Verifies a US ASCII encoded password string generated by cryptoPwhashStr()
crypto_pwhash_scryptsalsa208sha256() public static byte[] cryptoPwhashScryptSalsa208Sha256(byte[] key, byte[] passwd, byte[] salt, long opslimit, NativeLong memlimit)
crypto_pwhash_alg_argon2id13() (default in libsodium v1.0.15) public static int cryptoPwhashAlgArgon2id13() -
crypto_pwhash_alg_default() public static int cryptoPwhashAlgDefault() -
crypto_pwhash_saltbytes() public static int cryptoNumberSaltBytes() Length of salt
crypto_pwhash_saltbytes() public static int cryptoPwhashSaltBytes() Length of salt
crypto_pwhash_opslimit_interactive() public static long cryptoPwHashOpsLimitInteractive() -
crypto_pwhash_memlimit_interactive() public static NativeLong cryptoPwHashMemLimitInterative() -
crypto_pwhash_scryptsalsa208sha256_saltbytes() public static NativeLong cryptoPwHashScryptSalsa208Sha256SaltBytes() -

APIs

Load the libsodium C Library first

Before making call to any API, the native sodium C library must be loaded explicitly from a specific path. It is possible to load the library from path, however libsodium-jna is designed to load sodium library explicitly from a path.

Example: Load the native libsodium library

private static String libraryPath = null;

if (Platform.isMac())
{
    // MacOS
    libraryPath = "/usr/local/lib/libsodium.dylib";
    libraryPath = libraryPath;
    logger.info("Library path in Mac: " + libraryPath);
}
else if (Platform.isWindows())
{
    // Windows
    libraryPath = "C:/libsodium/libsodium.dll";
    logger.info("Library path in Windows: " + libraryPath);
}
else
{
    // Linux
    libraryPath = "/usr/local/lib/libsodium.so";
    logger.info("Library path: " + libraryPath);
}

logger.info("loading libsodium...");
SodiumLibrary.setLibraryPath(libraryPath);
// To check the native library is actually loaded, print the version of 
// native sodium library
String v = SodiumLibrary.libsodiumVersionString();
logger.info("libsodium version: " + v);
}

If the library could not be loaded Java's RuntimeException will be thrown. If the library is loaded successfully, you are ready to make the API calls.

Please look at TestInitializeLibrary.java to see how the library can be initialized from a static block.

Version of sodium library

/**
 * Return the version of native sodium library. After loading the native C library, it is a good idea 
 * to make this call to make sure that the expected version of the sodium library is loaded.
 */
public static String libsodiumVersionString()

Example: Print libsodium version

Make sure to Load the libsodium C Library first

  logger.info("libsodium version: " + SodiumLibrary.libsodiumVersionString());

Generate random data

/**
 * Return unpredictable sequence of bytes.
 *
 * Excerpt from libsodium documentation:
 * 
 *  - On Windows systems, the RtlGenRandom() function is used
 *  - On OpenBSD and Bitrig, the arc4random() function is used
 *  - On recent Linux kernels, the getrandom system call is used (since Sodium 1.0.3)
 *  - On other Unices, the /dev/urandom device is used
 *  - If none of these options can safely be used, custom implementations can easily be hooked.
 *
 * Parameters:
 *   size Number of random bytes to generate
 *
 * Return:
 *   Array of random bytes
 */
 public static byte[] randomBytes(int size)

Example: Generate random data

Make sure to Load the libsodium C Library first

// generate 16 bytes of random data
byte[] randomBytes = SodiumLibrary.randomBytes(16);
String hex = SodiumUtils.binary2Hex(salt);

// generate libsodium's standard number of salt bytes
int n = SodiumLibrary.cryptoNumberSaltBytes();
logger.info("Generate " + n + " random bytes");
byte[] salt = SodiumLibrary.randomBytes(n);
logger.info("Generated " + salt.length + " random bytes");
String hex = SodiumUtils.binary2Hex(salt);
logger.info("Random bytes: " + hex);

Secret-key authenticated cryptography

Excerpt from libsodium documentation:

This operation:

  • Encrypts a message with a key and a nonce to keep it confidential
  • Computes an authentication tag. This tag is used to make sure that the message hasn't been tampered with before decrypting it.

A single key is used both to encrypt/sign and verify/decrypt messages. For this reason, it is critical to keep the key confidential. The nonce doesn't have to be confidential, but it should never ever be reused with the same key. The easiest way to generate a nonce is to use randombytes_buf().

Make sure to Load the libsodium C Library first

Encrypt a message with a key and a nonce

/**
 * Encrypts a message with a key and a nonce
 *
 * Parameters:
 *  message    message bytes to encrypt
 *  nonce      nonce bytes. Generate it by calling  public static NativeLong cryptoBoxNonceBytes()
 *
 * Returns:
 *  Encrypted cipher text bytes 
 *
 * Throws SodiumLibraryException in case of error
 */

public static byte[] crytoSecretBoxEasy(byte[] message, byte[] nonce, byte[] key)

Verify and decrypt the message

/**
 * Verify and decrypt the message encrypted with crytoSecretBoxEasy()
 *
 * Parameters:
 *   cipherText  - encrypted bytes
 *   nonce        - nonce bytes used during encryption
 *   key          - key bytes used in encryption
 * 
 * Returns:
 *   Decrypted message bytes
 *  
 * Throws SodiumLibraryException in case of error
 */
public static byte[] cryptoSecretBoxOpenEasy(byte[] cipherText,byte[] nonce, byte[] key)

Example: Encrypt and Decrypt a message

Make sure to Load the libsodium C Library first

// don't forget to load the libsodium library first

String message = "This is a message";

// generate nonce
int nonceBytesLength = SodiumLibrary.cryptoSecretBoxNonceBytes().intValue();
byte[] nonceBytes = SodiumLibrary.randomBytes(nonceBytesLength);
byte[] messageBytes = message.getBytes();

// generate the encryption key
byte[] key = SodiumLibrary.randomBytes(SodiumLibrary.cryptoSecretBoxKeyBytes().intValue());

// encrypt
byte[] cipherText = SodiumLibrary.cryptoSecretBoxEasy(messageBytes, nonceBytes, key);

// now decrypt
byte[] decryptedMessageBytes = SodiumLibrary.cryptoSecretBoxOpenEasy(cipherText, nonceBytes, key);
String decryptedMessage;
try
{
    decryptedMessage = new String(decryptedMessageBytes, "UTF-8");
    System.out.println("Decrypted message: " + decryptedMessageBytes);
} catch (UnsupportedEncodingException e)
{
    e.printStackTrace();
}

Public-key cryptography

Generate Key Pair

Make sure to Load the libsodium C Library first

/**
 * Randomly generates a secret key and a corresponding public key
 *
 * Return:
 *   SodiumKeyPair
 */
 public static SodiumKeyPair cryptoBoxKeyPair()

Example: Generate key pair

// generate key pair
 SodiumKeyPair kp  = SodiumLibrary.cryptoBoxKeyPair();
 byte[] publicKey  = kp.getPublicKey();
 byte[] privateKey = kp.getPrivateKey();

 String hexPublicKey  = SodiumUtils.binary2Hex(publicKey);
 String hexPrivateKey = SodiumUtils.binary2Hex(privateKey);
/**
 * Alice encrypts a message with recipient's (Bob) public key and 
 * creates authentication tag with her private key
 * 
 * Parameters:
 *   message            The message to encrypt
 *   nonce              SodiumLibrary.crytoBoxNonceBytes() bytes of nonce. 
 *                      It must be preserved because it will be needed during decryption
 *   recipientPublicKey Recipient's public key for encrypting the message
 *   senderPrivateKey   Sender's private key for creating authentication tag
 *
 * Returns:
 *    encrypted message as an array of bytes
 */
 public static byte[] cryptoBoxEasy(byte[] message, 
    byte[] nonce
    byte[] recipientPublicKey, byte[] senderPrivateKey) throws SodiumLibraryException
/**
 * Bob (recipient) verifies the message with Alice's (sender) public key and 
 * decrypts the message with his private key
 *
 * Parameters:
 *  cipherText          Message to decrypt
 *  nonce               Nonce used during encryption 
 *  senderPublicKey     Sender's (Alice) public key for verifying message
 *  recipientPrivateKey Recipient's (Bob)  Private key to decrypt the message
 * 
 * Returns: 
 * Decrypted message as an array of bytes.
 * In case of error SodiumLibraryException() run time exception will be thrown 
 */
 public static byte[] cryptoBoxOpenEasy(byte[] cipherText,
    byte[]nonce, 
    byte[] senderPublicKey, byte[] recipientPrivateKey) throws SodiumLibraryException
/**
 * Encrypts a message with recipient's public key.
 * 
 * Usage: Alice can anonymously send a message to Bob by encrypting the message 
 * with his public key.
 * 
 * Parameters:
 *  message           The message bytes to encrypt
 * recipientPublicKey Recipient's public key 
 *
 * Rreturn:
 * Encrypted message bytes. The length of the cipher text will be 
 * SodiumLibrary#cryptoBoxSealBytes() + message.length
 *
 * Tthrows SodiumLibraryException on error
 */
 public static byte[] cryptoBoxSeal(byte[] message, byte[] recipientPublicKey) 
    throws SodiumLibraryException
/**
 * Decrypts a ciphertext using recipient's  key pair.
 * 
 * Only the recipient can decrypt the message with his private key but the 
 * recipient can not identify the sender.
 * 
 * Parameters:
 *  cipherText Ciphertext to decrypt
 *  pk Recipient's public key
 *  sk Recipient's private Key
 *
 * Returns:
 * Decrypted plaintext bytes. 
 * @throws SodiumLibraryException on error
 */
public static byte[] cryptoBoxSealOpen(byte[] cipherText,byte[] pk, byte[] sk) throws SodiumLibraryException

Example: Alice shares secret with Bob, Bob verifies and decrypt it

  1. Alice generates her key pair
  2. Bob generate his key pair
  3. Alice (sender) Encrypts a message with Bob's (recipient) public key and creates authentication tag with her private key
  4. Bob (recipient) verifies the message with Alice's (sender) public key and decrypts with his private key
// Alice generates key pair
SodiumKeyPair aliceKeyPair = SodiumLibrary.cryptoBoxKeyPair();
byte[] alicePublicKey = aliceKeyPair.getPublicKey();
byte[] alicePrivateKey = aliceKeyPair.getPrivateKey();

// Bob generates key pair
SodiumKeyPair bobKeyPair = SodiumLibrary.cryptoBoxKeyPair();
byte[] bobPublicKey = bobKeyPair.getPublicKey();
byte[] bobPrivateKey = bobKeyPair.getPrivateKey();

// Generate nonce
// This API will be changed to return int in future version of libsodium-jna
byte[] nonce = SodiumLibrary.randomBytes(SodiumLibrary.cryptoBoxNonceBytes().intValue());

String secretMessage = "Hi Bob, This is Alice";
// Alice encrypts the message with Bob's public key, creates authentication tag
// with her private key
byte[] cipherText = SodiumLibrary.cryptoBoxEasy(
    secretMessage.getBytes(), nonce, 
    bobPublicKey,
    alicePrivateKey);
String cipherHex = SodiumUtils.binary2Hex(cipherText);
logger.info("Ciphertext: " + cipherHex);

// Bob Verifies with Alice's public key and decrypts ciphertext with his Private key
byte[] decrypted = SodiumLibrary.cryptoBoxOpenEasy(
        cipherText, nonce,
        alicePublicKey,
        bobPrivateKey);
String decrypteString;
try
{
    decrypteString = new String(decrypted, "UTF-8");
    logger.info("decrypted: " + decrypteString);
} catch (UnsupportedEncodingException e)
{
    e.printStackTrace();
}

Example: Alice (sender) anonymously encrypts message with Bob's (recipient) public key

// Bob generates key pair
SodiumKeyPair bobKeyPair = SodiumLibrary.cryptoBoxKeyPair();
byte[] bobPublicKey = bobKeyPair.getPublicKey();
byte[] bobPrivateKey = bobKeyPair.getPrivateKey();

String secretMessage = "Hi Bob, This is Alice";
// Alice encrypts with Bob's public key
byte[] cipherText = SodiumLibrary.cryptoBoxSeal(secretMessage.getBytes(), bobPublicKey);
String cipherHex = SodiumUtils.binary2Hex(cipherText);
logger.info("Ciphertext: " + cipherHex);
logger.info("Ciphertext length : " + cipherText.length);

long ciperTextlength = SodiumLibrary.cryptoBoxSealBytes() + secretMessage.length();
logger.info("length: " + ciperTextlength);

Example: Bob (recipient) decrypts the message with his private key

// Bob decrypts with his private key
byte[] decrypted = SodiumLibrary.cryptoBoxSealOpen(cipherText, bobPublicKey, bobPrivateKey);

try
{
    String decrypteString = new String(decrypted, "UTF-8");
    logger.info("decrypted: " + decrypteString);
} catch (UnsupportedEncodingException e)
{
    e.printStackTrace();
}

Password hashing, key generation

From libsodium documentation:

Password hashing functions derive a secret key of any size from a password and a salt.

  • The generated key has the size defined by the application, no matter what the password length is.
  • The same password hashed with same parameters will always produce the same output.
  • The same password hashed with different salts will produce different outputs.
  • The function deriving a key from a password and a salt is CPU intensive and intentionally requires a fair amount of memory. Therefore, it mitigates brute-force attacks by requiring a significant effort to verify each password.

Derive Key from password

/**
 * Derives a key from a password and the given salt using Argon2i 
 *
 * Parameters:
 *  password    The password
 *  salt        The salt. The salt must be SodiumLibrary.cryptoPwhashSaltBytes() bytes long
 *
 * Comments:
 *  This method uses:
 *   opslimit as crypto_pwhash_opslimit_interactive()
 *   memlimit as crypto_pwhash_memlimit_interactive()
 *   algorithm as crypto_pwhash_alg_argon2id13() (default n libsodium v1.0.15)
 *
 * Returns:
 *  The derived key as array of bytes. 
 * In case of error SodiumLibraryException() run time exception will be thrown 
 */
public static byte[] cryptoPwhashArgon2i(byte[] passwd, byte[] salt) throws SodiumLibraryException

Make sure to Load the libsodium C Library first

Example: Derive key from password

  String passPhrase = "This is a passphrase";
  byte[] salt = SodiumLibrary.randomBytes(SodiumLibrary.cryptoPwhashSaltBytes());
  String hex = SodiumUtils.binary2Hex(salt);

  // create salt for deriving key from the pass phrase
  // salt is public but needs to be saved
  logger.info("Generated " + salt.length + " bytes of salt");
  logger.info(hex);
  logger.info("Derive key from passphrase");
  byte[] key = SodiumLibrary.cryptoPwhashArgon2i(passPhrase.getBytes(), salt);
  logger.info("Derived " + key.length + " bytes long key");
  hex = SodiumUtils.binary2Hex(key);
  logger.info(hex);

  // Later when you need to derive the key from the passphrase, use the saved salt 

Derive US-ASCII encoded key from password for storing

/**
 * Returns a US-ASCII encoded key derived from the password. The key can be stored for 
 * verification. 
 *
 * Parameters:
 *  password  The password
 *
 * Comments:
 *  Memory-hard, CPU-intensive hash function is applied to the
 *  password in key generation process.
 *
 *  Automatically generated salt is used in the key generation
 *
 *  Uses opslimit as crypto_pwhash_opslimit_interactive()
 *  Uses memlimit as crypto_pwhash_memlimit_interactive()
 *  
 * Returns:
 *  derived key as US-ASCII encoded string
 */
public static String cryptoPwhashStr(byte[] password) throws SodiumLibraryException

Make sure to Load the libsodium C Library first

Example: Dervice key from password as US-ASCII string

    String password = new String("বাংলা");
		// convert to UTF-8 encoded bytes
		byte[] passwordBytes = password.getBytes(StandardCharsets.UTF_8); // requires jdk 1.7+
		String key = SodiumLibrary.cryptoPwhashStr(passwordBytes);

Verify Stored US-ASCII encoded key with password

/**
 * Verify a US-ASCII encoded key derived previously by calling 
 * cryptoPwhashStr()
 *
 * Parameters:
 *  key         US-ASCII encoded key to verify
 *  password    The password
 *
 * Returns:
 *  true if the key can be verified, false otherwise
 */
 public static boolean cryptoPwhashStrVerify(String usAsciiKey, 
    byte[] password)

Make sure to Load the libsodium C Library first

Example: Verify US-ASCII encoded string

String password = new String("বাংলা");
// convert to UTF-8 encoded bytes
byte[] passwordBytes = password.getBytes(StandardCharsets.UTF_8); // requires jdk 1.7+
String key = SodiumLibrary.cryptoPwhashStr(passwordBytes);
// verify the password
boolean rc = SodiumLibrary.cryptoPwhashStrVerify(key, passwordBytes);
if (rc)
{
    logger.info("Password is verified");
}

How to encrypt a private key

This instruction is for encrypting something with a symmetric memory hardened key derived from a passphrase and use that key in encryption. I am giving the example on encrypting a private key as this is a very common requirement.

When the public and private key pair is generated and if it is required to store the private key, the private key must be properly encrypted and stored. The following procedure can be used to encrypt the private key:

Encrypting the private key

  • Come up with a strong pass phrase. Use a long memorable pass phrase. This is the most important defense against brute force cracking.

  • Generate cryptoPwhashSaltBytes() long salt

  byte[] salt = SodiumLibrary.randomBytes(SodiumLibrary.cryptoPwhashSaltBytes);
  • Derive a brute force resistant key from the pass phrase
  byte[] key = SodiumLibrary.cryptoPwhashArgon2i(passPhrase, salt);
  • Store the salt. This will be used to derive the same key again from the pass phrase

  • Generate cryptoSecretBoxNonceBytes() long nonce

  byte[] nonce = SodiumLibrary.randomBytes(SodiumLibrary.cryptoSecretBoxNonceBytes().intValue());
  • Encrypt the private key
  byte[] encryptedPrivateKey = SodiumLibrary.cryptoSecretBoxEasy(privateKey, nonce, key);
  • Store nonce and the encrypted private key

Decrypting the private key

  • Derive the encryption key from the pass phrase and stored salt
  byte[] key = SodiumLibrary.cryptoPwhashArgon2i(passPhraseBytes, saltBytes);
  • Verify and decrypt the private key with the derived key and stored nonce
  byte[] privateKey = SodiumLibrary.cryptoSecretBoxOpenEasy(encryptedPrivateKey, nonce, key);

If your project is not a maven project

If your project is not a maven project, find out the dependencies of libsodium-jna and obtain the jar files from maven central manually and add them to your build path

  • find the dependencies
    $ cd libsodium-jna
    $ mvn dependency:tree
...
[INFO] ------------------------------------------------------------------------
[INFO] Building com.muquit.libsodiumjna 1.0.1
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ libsodium-jna ---
[INFO] com.muquit.libsodiumjna:libsodium-jna:jar:1.0.1
[INFO] +- net.java.dev.jna:jna:jar:4.2.2:compile
[INFO] +- org.slf4j:slf4j-api:jar:1.7.21:compile
[INFO] +- org.slf4j:slf4j-log4j12:jar:1.7.21:compile
[INFO] |  \- log4j:log4j:jar:1.2.17:compile
[INFO] +- commons-codec:commons-codec:jar:1.10:compile
[INFO] \- junit:junit:jar:4.11:test
[INFO]    \- org.hamcrest:hamcrest-core:jar:1.3:test
...    

License is MIT

MIT