{"id":19765692,"url":"https://github.com/openhft/chronicle-salt","last_synced_at":"2025-04-30T15:30:40.562Z","repository":{"id":38391502,"uuid":"118320881","full_name":"OpenHFT/Chronicle-Salt","owner":"OpenHFT","description":"Chronicle wrapper for the NaCl library","archived":false,"fork":false,"pushed_at":"2024-05-30T10:42:45.000Z","size":3770,"stargazers_count":30,"open_issues_count":1,"forks_count":18,"subscribers_count":16,"default_branch":"ea","last_synced_at":"2025-04-06T02:41:51.343Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/OpenHFT.png","metadata":{"files":{"readme":"README.adoc","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-01-21T09:23:06.000Z","updated_at":"2024-07-02T06:53:29.000Z","dependencies_parsed_at":"2023-01-29T10:37:18.618Z","dependency_job_id":"7eb6326c-1ff5-4506-b928-f319c0dd6428","html_url":"https://github.com/OpenHFT/Chronicle-Salt","commit_stats":null,"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenHFT%2FChronicle-Salt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenHFT%2FChronicle-Salt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenHFT%2FChronicle-Salt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenHFT%2FChronicle-Salt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/OpenHFT","download_url":"https://codeload.github.com/OpenHFT/Chronicle-Salt/tar.gz/refs/heads/ea","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251731883,"owners_count":21634681,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-12T04:19:08.352Z","updated_at":"2025-04-30T15:30:39.597Z","avatar_url":"https://github.com/OpenHFT.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"= Chronicle Salt - Java binding to wrap libsodium which implements the NaCl crypto library\n\nsee also https://en.wikipedia.org/wiki/NaCl_(software)\n\n[caption=\"\", link=https://maven-badges.herokuapp.com/maven-central/net.openhft/chronicle-salt]\nimage::https://maven-badges.herokuapp.com/maven-central/net.openhft/chronicle-salt/badge.svg[]\nimage:https://javadoc.io/badge2/net.openhft/chronicle-salt/javadoc.svg[link=\"https://www.javadoc.io/doc/net.openhft/chronicle-salt/latest/index.html\"]\n\nThis library natively supports Chronicle Bytes and can sign and verify data entirely off heap. This saves copying data to/from byte[] (not creating them)\n\n=== Based on\nThis library is a port of the https://github.com/abstractj/kalium[Abstractj Kalium] library to use Chronicle Bytes off heap instead of byte[] on heap.\n\nUsing off heap data directly improves performance and scalability.\n\n=== Requirements\n\n* JDK 8 or http://www.oracle.com/technetwork/java/javase/downloads/index.html[higher]\n* http://maven.apache.org/guides/getting-started/[Apache Maven]\n\n=== Installation\n\n==== libsodium\n\nChronicle Salt uses https://www.gitbook.com/book/jedisct1/libsodium/details[libsodium] wrapped via https://github.com/jnr/jnr-ffi[jnr-ffi]\n\nFor a more detailed explanation, please refer to\nhttps://github.com/cryptosphere/rbnacl/blob/master/README.md[RbNaCl's documentation]\n\n==== Linux\n\nLinux users can download the source tar for Linux\n\n- Download `libsodium` from https://download.libsodium.org/libsodium/releases/\n- Choose the version of `libsodium` you wish to use\n    - The archives follow the following pattern: libsodium-{version}.tar.gz\n- `tar xzvf libsodium-{version}.tar.gz`\n- `cd libsodium-{version}`\n- `./configure`\n- `make`\n- `sudo make install`\n- After this has released do a `mvn install` from the command line to build `libbridge`\n\n==== OSX\n\nOS X users can get libsodium via http://mxcl.github.com/homebrew/[homebrew] with:\n\n    brew install libsodium\n\n==== Windows\n\nWindows users will need to provide the pre-build binaries from `libsodium`.\n\n- Download `libsodium` from https://download.libsodium.org/libsodium/releases/\n- Choose the version of `libsodium` you wish to use\n    - The archives follow the following pattern: libsodium-{version}-msvc.zip\n- From the archive find the artifacts compiled for your architecture and then the MSVC tool set of your choice\n    - For example: `v141 // these were compiled against the MSVC v141 (i.e. Visual Studio 2017)`\n- Extract from the archive the `dll` library files into **one** of the following locations:\n    - into the `lib` at the root of the working directory directory of your project.\n    - into a location that is included in your `PATH` environment variable.\n\nFor example, on my Windows 10 machine with a x64 architecture:\n```\n{archive root}\n└───x64\n    ...\n    └───Release\n        ...\n        └───v141\n            ...\n            └───dynamic \u003c- copy the library files from this locaiton.\n```\n\n== Private (Secret) and Public Keys and Ed25519 Signatures\n\n=== Private (Secret) Keys\n\n - One of two keys used in public key cryptography.\n - It is used to sign digital signatures and to decrypt data that was encoded using the recipient's public key.\n - The private key is not visible to the public; it is only visible to the owner.\n - https://www.techopedia.com/definition/16135/private-key[Detailed definition]\n \n=== Public Keys\n\n  - One of two keys used in public key cryptography.\n  - The public key is used to encrypt the message receieved, and is assumed visibe to everyone.\n  - https://en.wikipedia.org/wiki/Public-key_cryptography[Detailed definition]\n\n=== Ed25519 Signatures\n\n - Elliptic-curve signatures.\n - Engineered at several levels of design and implementation to achieve very high speeds without compromising security.\n - https://en.wikipedia.org/wiki/EdDSA[Detailed definition]\n \n== Using Chronicle Salt\n\n=== Generating Random Bytes\n\n - Random bytes are used to form a private key as it ensures they key is difficult to guess, therefore more secure.\n\n.Generating random bytes which could be used for a private key\n[source, Java]\n----\n    Bytes\u003c?\u003e rand = Ed25519.generateRandomBytes(32);\n----\n \n=== Generating a public and secret key from a seed\n\n - A public and secret key need to be generated as they are used to sign a message, making it secure and allowing the receiver              authenticate the sender/message.\n \n.Generating private first and then a public and secret key\n[source, Java]\n----\n    Bytes\u003c?\u003e privateKey = Ed25519.generatePrivateKey();\n\n    Bytes\u003c?\u003e publicKey = Bytes.allocateElasticDirect();\n    Bytes\u003c?\u003e secretKey = Bytes.allocateElasticDirect();\n\n    Ed25519.privateToPublicAndSecret(publicKey, secretKey, privateKey);\n----\n\nNOTE: The secret key holds the private AND public key and is needed for some operations.\n\n=== Viewing keys as a hexadecimal dump\n\n.Viewing all three keys\n[source, Java]\n----\n    System.out.println(privateKey.toHexString());\n    System.out.println(publicKey.toHexString());\n    System.out.println(secretKey.toHexString());\n----\n\nPrints something like\n\n.private, public and secret keys\n----\n00000000 54 c8 b8 05 5a df 56 9f  8a ae b4 72 2c 69 26 42 T···Z·V· ···r,i\u0026B\n00000010 99 c6 d4 36 13 4c cc 2b  83 04 da c5 71 75 b0 1a ···6·L·+ ····qu··\n\n00000000 95 65 db 8d 48 06 12 ae  c4 fe 44 c1 d9 07 5f 19 ·e··H··· ··D···_·\n00000010 19 de 6b 13 cc 24 67 27  3a bf 9b ce 25 c8 a1 33 ··k··$g' :···%··3\n\n00000000 54 c8 b8 05 5a df 56 9f  8a ae b4 72 2c 69 26 42 T···Z·V· ···r,i\u0026B\n00000010 99 c6 d4 36 13 4c cc 2b  83 04 da c5 71 75 b0 1a ···6·L·+ ····qu··\n00000020 95 65 db 8d 48 06 12 ae  c4 fe 44 c1 d9 07 5f 19 ·e··H··· ··D···_·\n00000030 19 de 6b 13 cc 24 67 27  3a bf 9b ce 25 c8 a1 33 ··k··$g' :···%··3\n----\n\n=== Signing a message\n\nAfter creating a message, it can be signed.\n\nNOTE: The `signatureAndMsg` includes the signature and the messages as this is the way the underlying library is written.\n\n.Signing a message\n[source, Java]\n----\n    Bytes\u003c?\u003e signatureAndMsg = Bytes.allocateElasticDirect();\n    // OR\n    Bytes\u003c?\u003e signatureAndMsg = Bytes.allocateDirect(Ed25519.SIGNATURE_LENGTH + message.readRemaining());\n    Ed25519.sign(signatureAndMsg, message, secretKey);\n----\n\nNOTE: The `sign` method appends, rather than overwrites the `signatureAndMsg`. If you want to overwrite, you need to call `clear()` first\n\n.Signing two messages\n[source, Java]\n----\n    Bytes\u003c?\u003e signatureAndMsg = Bytes.allocateElasticDirect();\n    Ed25519.sign(signatureAndMsg, message, secretKey);\n    Ed25519.sign(signatureAndMsg, message2, secretKey); // \u003c1\u003e\n----\n\u003c1\u003e signatureAndMsg now contains two messages\n\n.Signing two messages with overwriting\n[source, Java]\n----\n    Bytes\u003c?\u003e signatureAndMsg = Bytes.allocateElasticDirect();\n    Ed25519.sign(signatureAndMsg, message, secretKey); // \u003c1\u003e \n    client.write(signatureAndMsg);\n\n    signatureAndMsg.clear()\n    Ed25519.sign(signatureAndMsg, message2, secretKey); // \u003c2\u003e\n    client.write(signatureAndMsg);\n----\n\u003c1\u003e first message signed\n\u003c2\u003e signatureAndMsg contains one message\n\n=== Verifying a message\n\nOnce a message has been signed, you can verify it using the public key alone.\n\n.Verifying a message\n[source, Java]\n----\n    boolean verified = Ed25519.verify(signatureAndMsg, publicKey);\n----\n - Verifying a message is a means of authenticating that a message is received from a certain sender.\n - The digital signature, put simply, is a hash of the data (message, file, etc.).\n - To validate a message, the receipient calculates the hash of the same data and will use the senders public key to decrypt the digital    signature. \n - The two hash values are compared - if they match, the signature is considered valid. If they don't match, it can mean that another      signature was used to sign it, or the data was (intentionally or unintentionally) altered.\n - If the hash values do not match, the message will not be verified.\n - Using the public key to verify a message ensures you are receiving a genuine message from the sender, and that it hasn't been altered    in any way.\n\n== Public-Key Cryptography\nPublic-key cryptography requires two different keys: a public key which can be shared and is used to encrypt or authenticate a message,\nand a complementary private key which must be kept secret and is used to decrypt or sign a message. Chronicle-Salt wraps public-key cryptography\nin the `EasyBox` class (reflecting the underlying Sodium `crypto_box_easy interface`).\n\n=== Authenticated encryption\nA sender (Bob) can encrypt a confidential message for a specific receiver (Alice) using Alice's public key.\nUsing either Alice's public key and Bob's private key, or Bob's public key and Alice's private key, the (same) shared secret key can be\ncomputed. This shared secret is used to verify an encrypted message has not been tampered with.\n\nEach message exchanged between two users should also have an associated nonce. This is some arbitrary additional data which is folded\ninto the encryption, and is used to ensure that old communications cannot be simply reused as part of a replay attack.\nCrucially, for this to be effective, a nonce should never be re-used when encrypting messages between a given sender/receiver.\nIn some applications, the nonce can be used as a form of message sequencer in which case a simple incrementing counter between messages\nis acceptable. Otherwise, the nonce would normally be refreshed/stirred between messages. A nonce does not need to be confidential.\n\n=== Key Pair Generation\nA public/private key pair can be generated as follows:\n[source, Java]\n----\nEasyBox.KeyPair keys = EasyBox.KeyPair.generate();\n----\n\nThe above will generate a random key pair on each call. In some cases (such as testing) it is useful to have a deterministic key pair.\nChronicle-Salt provides two options for this. The first is a simplistic but convenient call taking a `long` seed value, providing 64 seed bits:\n[source, Java]\n----\nEasyBox.KeyPair keys = EasyBox.KeyPair.deterministic(123);\n----\n\nAlternatively, a 32-byte `BytesStore` can be used, providing control over the full 256 seed bits, eg:\n[source, Java]\n----\nBytesStore seed = NativeBytesStore.from(\"01234567890123456789012345678901\");\nEasyBox.KeyPair keys = EasyBox.KeyPair.deterministic(seed);\n----\n\n=== Securely Wiping Keys\nSensitive data in general, and secret components of key pairs in particular, should be overwritten when no longer required.\nChronicle-Salt provides convenient calls wrapping `sodium_memzero()` which attempts to securely zero a range of memory vs `memset`\nand similar which may be silently stripped by some optimisations.\n\nOnce a key pair is no longer needed, the following should be called to securely clear the data:\n[source, Java]\n----\nvoid KeyPair.wipe();\n----\n\n=== Nonce Generation\nNonces are arbitrary 32-byte sequences and can be generated in much the same way as key pairs:\n[source, Java]\n----\n// generate a random nonce\nEasyBox.Nonce nonce = EasyBox.Nonce.generate();\n\n// deterministic option 1: simplistic long/64-bit seed\nEasyBox.Nonce nonce = EasyBox.Nonce.deterministic(123);\n\n// deterministic option 2: 32-byte/256-bit seed\nBytesStore seed = NativeBytesStore.from(\"01234567890123456789012345678901\");\nEasyBox.Nonce nonce = EasyBox.Nonce.deterministic(seed);\n----\n\nAs described above, a given nonce value should never be re-used across messages between the same two parties. Given a nonce, a new value\ncan be obtained in one of two ways depending on the use case:\n[source, Java]\n----\n// standard randomising call\nnonce.stir();\n\n// increment by 1, eg useful as a form of message sequencer\nnonce.next();\n----\n\n=== Encryption/Decryption\nGiven two key pairs and a fresh nonce, a message can be sent between two parties using the recipient's public key and the sender's private key eg:\n[source, Java]\n----\nBytesStore message = NativeBytesStore.from(\"test message\");\n\n// Generate the key pairs and nonce\nEasyBox.KeyPair alice = EasyBox.KeyPair.generate();\nEasyBox.KeyPair bob = EasyBox.KeyPair.generate();\nEasyBox.Nonce nonce = EasyBox.Nonce.generate();\n\n// Alice sends to Bob\nBytesStore cipherText = EasyBox.encrypt(message, nonce, bob.publicKey, alice.secretKey);\n\n// Bob decrypts the message\nBytesStore clearText = EasyBox.decrypt(cipherText, nonce, alice.publicKey, bob.secretKey);\n\n// clear sensitive data when done\nalice.wipe();\nbob.wipe();\n----\n\nThe `decrypt` call will throw an `IllegalStateException` if the decryption step fails for any reason.\n\nThe above creates the cipherText and clearText `BytesStores` as needed. Optionally an existing `BytesStore`\ncan be provided, although the user needs to ensure sufficient size:\n[source, Java]\n----\n// ... as above\n\n// Alice sends to Bob\nEasyBox.encrypt(cipherText, message, nonce, bob.publicKey, alice.secretKey);\n\n// Bob decrypts the message\nEasyBox.decrypt(clearText, cipherText, nonce, alice.publicKey, bob.secretKey);\n----\n\nThe above interfaces are strongly-typed on nonce, public key, and private key which helps to avoid mistakes from accidentally\ntransposing arguments. This is the recommended approach, however a lower level interface taking explicit `BytesStores` is available and\nmay be preferrable in some situations:\n[source, Java]\n----\nEasyBox.KeyPair alice = EasyBox.KeyPair.generate();\nEasyBox.KeyPair bob = EasyBox.KeyPair.generate();\n\nBytesStore alicePublicKey = alice.publicKey.store; // or some other manually managed area\nBytesStore aliceSecretKey = alice.secretKey.store; // or some other manually managed area\nBytesStore bobPublicKey = bob.publicKey.store;     // or some other manually managed area\nBytesStore bobSecretKey = bob.secretKey.store;     // or some other manually managed area\n\nBytesStore nonce = ...;\n\n// Alice sends to Bob\nEasyBox.encrypt(cipherText, message, nonce, bobPublicKey, aliceSecretKey);\n\n// Bob decrypts the message\nEasyBox.decrypt(clearText, cipherText, nonce, alicePublicKey, bobSecretKey);\n----\n\n=== Precalculation/Multiple messages\nThe standard encryption/decryption interface described above internally calculates a shared secret key (from the public and private\nkeys passed in the encrypt/decrypt calls respectively). Where it is known that a number of messages will be sent between the same two\nparties, this shared secret key can be calculated once and reused on each operation, resulting in much improved performance.\n\nAs with standard key pairs, a `SharedKey` should be wiped when no longer required.\n\n[source, Java]\n----\nBytesStore message = NativeBytesStore.from(\"test message\");\n\nEasyBox.KeyPair alice = EasyBox.KeyPair.generate();\nEasyBox.KeyPair bob = EasyBox.KeyPair.generate();\nEasyBox.Nonce nonce = EasyBox.Nonce.generate();\n\n// precalculate the shared secret key\nEasyBox.SharedKey shared = EasyBox.SharedKey.precalc( alice, bob );\n\nfor (int i=0; i\u003c1000; ++i)\n{\n    BytesStore cipherText = EasyBox.encryptShared(message, nonce, shared);\n    BytesStore clearText  = EasyBox.decryptShared(ciphertext, nonce, shared);\n\n    // increment the nonce, or alternatively use nonce.stir()\n    nonce.next();\n}\n\n// clear sensitive data when done\nalice.wipe();\nbob.wipe();\nshared.wipe();\n----\n\n=== Anonymous Sender/Sealed Boxes\nA reduced form of public-key cryptography can be used to anonymously send a message to a recipient given the recipient's public key.\nChronicle-Salt wraps anonymous sender public-key cryptography in the `SealedBox` class (reflecting the underlying Sodium `crypto_box_seal` interface).\nA recipient can decypt a `SealedBox` message using their private key, but it is not possible to verify the identity of the sender.\nThe integrity of the message itself can however be verified.\n\nInternally, an ephemeral key pair is used on the sender's side when encrypting a `SealedBox` message. This ephemeral key is not\nexposed by the underlying Sodium library, and cannot be controlled. For this reason there are no \"deterministic\" calls in the\n`SealedBox` interface, as while one public/private key pair could be deterministic the ephemeral key pair could not, meaning the\nciphertext would vary from run to run.\n\nThe form of the `SealedBox` calls closely follows `EasyBox` (minus the nonce and second key pair), for example to encrypt/decrypt:\n[source, Java]\n----\nBytesStore message = NativeBytesStore.from(\"test message\");\n\nSealedBox.KeyPair keys = SealedBox.KeyPair.generate();\n\n// Alice (anonymously) encrypts a message using Bob's public key\nBytesStore ciphertext = SealedBox.encrypt(message, keys.publicKey);\n\n// Bob decrypts the message using his own public and private keys\nBytesStore cleartext = SealedBox.decrypt(ciphertext, keys.publicKey, keys.secretKey);\n\n// clear sensitive data when done\nkeys.wipe();\n----\n\nThe `decrypt` call will throw an `IllegalStateException` if the decryption step fails for any reason.\n\nAs for the `EasyBox` interface, an existing `BytesStore` can optionally be provided for the encrypt/decrypt call if preferred:\n[source, Java]\n----\n// ... as above\n\n// Alice (anonymously) encrypts a message using Bob's public key\nSealedBox.encrypt(ciphertext, message, keys.publicKey);\n\n// Bob decrypts the message using his own public and private keys\nSealedBox.decrypt(cleartext, ciphertext, keys.publicKey, keys.secretKey);\n----\n\nThe above interfaces are strongly-typed on public/private key which helps to avoid mistakes from accidentally\ntransposing arguments. This is the recommended approach, however a lower level interface taking explicit `BytesStores` is available and\nmay be preferrable in some situations:\n[source, Java]\n----\nSealedBox.KeyPair keys = SealedBox.KeyPair.generate();\n\nBytesStore publicKey = keys.publicKey.store; // or some other manually managed area\nBytesStore secretKey = keys.secretKey.store; // or some other manually managed area\n\n// Alice sends to Bob\nSealedBox.encrypt(cipherText, message, publicKey);\n\n// Bob decrypts the message\nSealedBox.decrypt(clearText, cipherText, publicKey, secretKey);\n----\n\n=== Public-Key Signatures\nGiven a trusted public key from a particular sender, recipients can verify messages signed using the sender's private key\n  originated from the sender and have not subsequently been tampered with.\n\nNote, this mechanism is used only to verify the source and integrity of a message. The message content itself is not changed in any\nway so this is not suitable for protecting sensitive data. For that use case, see the encryption/decryption support above.\n\nChronicle-Salt wraps public-key signatures in the `Signature` class, which in turn is built on the underlying Sodium\n`crypto_sign` interface. The form of the `Signature` calls closely follows `EasyBox`, but with just one key pair, and sign/verify\ninstead of encrypt/decrypt.\n\nThe sender's key pair can be generated randomly, or deterministically using a seed for repeatable behaviour:\n[source, Java]\n----\n// generate a random key pair\nSignature.KeyPair keys = Signature.KeyPair.generate();\n\n// deterministic option 1: simplistic long/64-bit seed\nSignature.KeyPair keys = Signature.KeyPair.deterministic(123);\n\n// deterministic option 2: 32-byte/256-bit seed\nBytesStore seed = NativeBytesStore.from(\"01234567890123456789012345678901\");\nSignature.KeyPair keys = Signature.KeyPair.deterministic(seed);\n----\n\nA message can then be signed and subsequently verified as follows:\n[source, Java]\n----\nBytesStore message = NativeBytesStore.from( \"test message\" );\n\nSignature.KeyPair keys = Signature.KeyPair.generate();\n\n// Sender signs the message using their secret key\nBytesStore signed = Signature.sign( message, keys.secretKey );\n\n// Recipient verifies the message using the sender's public key\nBytesStore unsigned = Signature.verify( signed, keys.publicKey);\n\n// clear sensitive data when done\nkeys.wipe();\n----\n\nThe `verify` call will throw an `IllegalStateException` if the verification step fails for any reason.\n\nAs for the `EasyBox` interface, an existing `BytesStore` can optionally be provided for the sign/verify call if preferred:\n[source, Java]\n----\n// ... as above\n\n// Sender signs the message using their secret key\nSignature.sign(signed, message, keys.secretKey);\n\n// Recipient verifies the message using the sender's public key\nSignature.verify(unsigned, signed, keys.publicKey);\n----\n\nThe above interfaces are strongly-typed on public/private key which helps to avoid mistakes from accidentally\nusing the wrong part. This is the recommended approach, however a lower level interface taking explicit `BytesStores` is available and\nmay be preferrable in some situations:\n[source, Java]\n----\nSignature.KeyPair keys = Signature.KeyPair.generate();\n\nBytesStore publicKey = keys.publicKey.store; // or some other manually managed area\nBytesStore secretKey = keys.secretKey.store; // or some other manually managed area\n\n// Sender signs the message using their secret key\nSignature.sign(signed, message, secretKey);\n\n// Recipient verifies the message using the sender's public key\nSignature.verify(unsigned, signed, publicKey);\n----\n\n=== Signatures for Multi-Part Messages\nIn addition to single-message signing as described above, it is also possible to generate a single secure signature for a collection\nof several arbitrarily-sized message parts. Where possible, the single-message interface described above should be preferred, however\nwhere multi-part messages are required Chronicle-Salt provides the `Signature.MultiPart` wrapper class.\n\nOnce a `MultiPart` message is initialised, individual message parts can be added using:\n[source, Java]\n----\nvoid Signtaure.MultiPart.add( BytesStore message );\n----\n\nThe signature for the collection of messages is then obtained using the signer's secret key:\n[source, Java]\n----\n// option 1 (preferred): pass strongly-typed secret key\nBytesStore Signature.MultiPart.sign( SecretKey sk );\n\n// option 2: pass explicit BytesStore representing secret key\nBytesStore Signature.MultiPart.sign( BytesStore secretkey );\n----\n\nOnce `sign` has been called the `MultiPart` object should not be used further without first being reset:\n[source, Java]\n----\nvoid Signature.MultiPart.reset();\n----\n\nThe recipient/verifier builds a multi-part wrapper in a similar fashion, then verifies the collection\nusing the signer's public key by calling:\n[source, Java]\n----\n// option 1 (preferred): pass strongly-typed public key\nvoid Signature.MultiPart.verify( BytesStore signature, PublicKey pk );\n\n// option 2: pass explicit BytesStore representing public key\nvoid Signature.MultiPart.verify( BytesStore signatire, BytesStore publickey );\n----\n\n`Verify` will throw an `IllegalStateException` if the call fails for any reason.\nOnce `verify` has been called the `MultiPart` object should not be used further without first being reset.\n\nThe following is a complete example illustrating signing and subsequently verifying a collection of messages:\n[source, Java]\n----\nBytesStore message1 = NativeBytesStore.from( \"Message part1\");\nBytesStore message2 = NativeBytesStore.from( \"Message part2\");\nBytesStore message3 = NativeBytesStore.from( \"Message part3\");\n\n// Generate the signer's key pair\nSignature.KeyPair keys = Signature.KeyPair.generate();\n\n// Initialise a MultiPart wrapper, and add multiple messages\nSignature.MultiPart multi = new Signature.MultiPart();\nmulti.add( message1 );\nmulti.add( message2 );\nmulti.add( message3 );\n\n// Generate the signature for the collection of messages using the signer's secret key\nBytesStore signature = multi.sign( keys.secretKey );\n\n// Initialise the recipient's MultiPart wrapper, and add the received multiple message parts\nSignature.MultiPart recv = new Signature.MultiPart();\nrecv.add( message1 );\nrecv.add( message2 );\nrecv.add( message3 );\n\n// Verify the signature using the signer's public key\nrecv.verify( signature, keys.publicKey );\n----\n\n=== Extracting Seed and Public Key from Signature Secret Key\nThe secret key used for public-key message signing includes within it the public key and seed (either random or deterministic\nas relevant). Given a signer's secret key, these seed can be extracted as follows:\n[source, Java]\n----\nBytesStore extractSeed();                 // extract seed; creates and returns a suitable BytesStore\nBytesStore extractSeed( BytesStore seed); // extract seed to provided BytesStore (which is returned)\n----\n\nThe public key can be extracted similarly:\n[source, Java]\n----\nBytesStore extractPublicKey();                // extract public key; creates and returns suitable BytesStore\nBytesStore extractPublicKey( BytesStore pk ); // extract public key to provided BytesStore\n----\n\nFor example:\n[source, Java]\n----\nBytesStore seed = NativeBytesStore.from( \"01234567890123456789012345678901\" );\nSignature.KeyPair keys = Signature.KeyPair.deterministic(seed);\n\nBytesStore seed2 = keys.secretKey.extractSeed();\nSystem.out.println(DatatypeConverter.printHexBinary(seed2.toByteArray()) );\n\nBytesStore pk = keys.secretKey.extractPublicKey();\nSystem.out.println(DatatypeConverter.printHexBinary(pk.toByteArray()) );\n----\n\nprints\n[source]\n----\n3031323334353637383930313233343536373839303132333435363738393031\n7BC3079518ED11DA0336085BF6962920FF87FB3C4D630A9B58CB6153674F5DD6\n----\n\n== SHA-2 Hashing\n\nA given message or data of arbitrary size can be deterministically hashed to a 32-byte or 64-byte value via standard\nSHA-256 or SHA-512 respectively. Chronicle-Salt supports various options for invoking the SHA-2 hash functions, as well\nas a multi-part API to support generating a hash for a sequence of messages/data.\n\n=== SHA-256 Hash\n\nThe SHA-256 hash of a message can be obtained using one of the following:\n[source, Java]\n----\nBytesStore SHA2.sha256( BytesStore message );                    // creates a BytesStore to hold the hash\nBytesStore SHA2.sha256( BytesStore result, BytesStore message ); // place hash in provided BytesStore\n----\n\nAlternatively, a SHA-256 hash can be appended to a given `Bytes` handle:\n[source, Java]\nvoid SHA2.appendSha256( Bytes\u003c?\u003e output, BytesStore message );\n\nFor example:\n[source, Java]\n----\n    BytesStore message = \"example message\";\n\n    // Option 1: Create and return the BytesStore\n    BytesStore hash = SHA2.sha256( message );\n\n    // Option 2: Use an existing BytesStore to hold the result\n    BytesStore hash = ...;\n    SHA2.sha256( hash, message );\n\n    // Option 3: append the hash to a given Bytes handle\n    Bytes\u003c?\u003e hash256 = Bytes.allocateDirect(SHA2.HASH_SHA256_BYTES));\n    SHA2.appendSha256(hash256, message);\n----\n\n=== SHA-512 Hash\n\nThe SHA-512 hash of a message can be obtained using one of the following:\n[source, Java]\n----\nBytesStore SHA2.sha512( BytesStore message );                    // creates a BytesStore to hold the hash\nBytesStore SHA2.sha512( BytesStore result, BytesStore message ); // place hash in provided BytesStore\n----\n\nAlternatively, a SHA-512 hash can be appended to a given `Bytes` handle:\n[source, Java]\nvoid SHA2.appendSha512( Bytes\u003c?\u003e output, BytesStore message );\n\nFor example:\n[source, Java]\n----\n    BytesStore message = \"example message\";\n\n    // Option 1: Create and return the BytesStore\n    BytesStore hash = SHA2.sha512( message );\n\n    // Option 2: Use an existing BytesStore to hold the result\n    BytesStore hash = ...;\n    SHA2.sha512( hash, message );\n\n    // Option 3: append the hash to a given Bytes handle\n    Bytes\u003c?\u003e hash512 = Bytes.allocateDirect(SHA2.HASH_SHA512_BYTES));\n    SHA2.appendSha512(hash512, message);\n----\n\n=== Multi-Part SHA-256 and SHA-512 Hashing\nIn addition to single-message hashing as described above, it is also possible to generate a single hash for a collection\nof several arbitrarily-sized message parts. Multi-part hashing is provided by the `SHA2.MultiPartSHA256` and\n`SHA2.MultiPartSHA512` wrapper classes.\n\nOnce a `MultiPartSHA256` or `512` message is initialised, individual message parts can be added using:\n[source, Java]\n----\nvoid SHA2.MultiPartSHA256.add( BytesStore message );\nvoid SHA2.MultiPartSHA512.add( BytesStore message );\n----\n\nThe hash for the collection of messages is then obtained as follows:\n[source, Java]\n----\nBytesStore SHA2.MultiPartSHA256.hash();                   // create a BytesStore to hold the hash\nBytesStore SHA2.MultiPartSHA256.hash( BytesStore result); // place hash in provided BytesStore\n\nBytesStore SHA2.MultiPartSHA512.hash();                   // create a BytesStore to hold the hash\nBytesStore SHA2.MultiPartSHA512.hash( BytesStore result); // place hash in provided BytesStore\n----\n\nOnce `hash` has been called the `MultiPartSHA256` or `512` object should not be used further without first\nbeing reset:\n[source, Java]\n----\nvoid SHA2.MultiPartSHA256.reset();\nvoid SHA2.MultiPartSHA512.reset();\n----\n\nThe following is a complete example generating the SHA-256 and SHA-512 hash of a collection of messages:\n[source, Java]\n----\nBytesStore message1 = NativeBytesStore.from( \"abcdefgh\");\nBytesStore message2 = NativeBytesStore.from( \"ijklmnop\");\nBytesStore message3 = NativeBytesStore.from( \"qrstuvwxyz\");\n\n// Initialise a MultiPartSHA256 wrapper\nSHA2.MultiPartSHA256 multi256 = new SHA2.MultiPartSHA256();\nmulti256.add( message1 );\nmulti256.add( message2 );\nmulti256.add( message3 );\n\n// Generate the single SHA-256 hash of the set of messages\nBytesStore hash256 = multi256.hash();\n\n// Initialise a MultiPartSHA512 wrapper\nSHA2.MultiPartSHA512 multi512 = new SHA2.MultiPartSHA512();\nmulti512.add( message1 );\nmulti512.add( message2 );\nmulti512.add( message3 );\n\n// Generate the single SHA-512 hash of the set of messages\nBytesStore hash512 = multi512.hash();\n\nSystem.out.println(\"SHA256: \" + DatatypeConverter.printHexBinary(hash256.toByteArray()));\nSystem.out.println(\"SHA512: \" + DatatypeConverter.printHexBinary(hash512.toByteArray()));\n----\n\nThe above prints the following, matching the hashes of the full message `abcdefghijklmnopqrstuvwxyz`:\n[source]\n----\nSHA256: 71C480DF93D6AE2F1EFAD1447C66C9525E316218CF51FC8D9ED832F2DAF18B73\n\nSHA512: 4DBFF86CC2CA1BAE1E16468A05CB9881C97F1753BCE3619034898FAA1AABE429\n        955A1BF8EC483D7421FE3C1646613A59ED5441FB0F321389F77F48A879C7B1F1\n----\n\n== Blake2b Hashing\n\nA given message or data of arbitrary size can be deterministically hashed to a 32-byte or 64-byte value via standard\nBlake2b and varying the output size length accordingly. Chronicle-Salt supports various options for invoking the\nBlake2b hash functions (or generic hash functions as they are called in the Sodium API), as well as a multi-part API\nto support generating a hash for a sequence of messages/data.\n\n=== Blake2b-256 Hash\n\nThe Blake2b-256 hash of a message can be obtained using one of the following:\n[source, Java]\n----\nBytesStore Blake2b.hash256( BytesStore message );                    // creates a BytesStore to hold the hash\nBytesStore Blake2b.hash256( BytesStore result, BytesStore message ); // place hash in provided BytesStore\n----\n\nAlternatively, a Blake2b-256 hash can be appended to a given `Bytes` handle:\n[source, Java]\nvoid Blake2b.append256( Bytes\u003c?\u003e output, BytesStore message );\n\nFor example:\n[source, Java]\n----\n    BytesStore message = \"example message\";\n\n    // Option 1: Create and return the BytesStore\n    BytesStore hash = Blake2b.hash256( message );\n\n    // Option 2: Use an existing BytesStore to hold the result\n    BytesStore hash = ...;\n    Blake2b.hash256( hash, message );\n\n    // Option 3: append the hash to a given Bytes handle\n    Bytes\u003c?\u003e hash256 = Bytes.allocateDirect(Blake2b.HASH_BLAKE2B_256_BYTES));\n    Blake2b.append256(hash256, message);\n----\n\n=== Blake2b-512 Hash\n\nThe Blake2b-512 hash of a message can be obtained using one of the following:\n[source, Java]\n----\nBytesStore Blake2b.hash512( BytesStore message );                    // creates a BytesStore to hold the hash\nBytesStore Blake2b.hash512( BytesStore result, BytesStore message ); // place hash in provided BytesStore\n----\n\nAlternatively, a Blake2b-512 hash can be appended to a given `Bytes` handle:\n[source, Java]\nvoid Blake2b.append512( Bytes\u003c?\u003e output, BytesStore message );\n\nFor example:\n[source, Java]\n----\n    BytesStore message = \"example message\";\n\n    // Option 1: Create and return the BytesStore\n    BytesStore hash = Blake2b.hash512( message );\n\n    // Option 2: Use an existing BytesStore to hold the result\n    BytesStore hash = ...;\n    Blake2b.hash512( hash, message );\n\n    // Option 3: append the hash to a given Bytes handle\n    Bytes\u003c?\u003e hash512 = Bytes.allocateDirect(Blake2b.HASH_BLAKE2B_512_BYTES));\n    Blake2b.append512(hash512, message);\n----\n\n=== Multi-Part Blake2b-256 and Blake2b-512 Hashing\n\nIn addition to single-message hashing as described above, it is also possible to generate a single hash for a collection\nof several arbitrarily-sized message parts. Multi-part hashing is provided by the `Blake2b.MultiPart256` and\n`Blake2b.MultiPart512` wrapper classes.\n\nOnce a `MultiPart256` or `MultiPart512` message is initialised, individual message parts can be added using:\n[source, Java]\n----\nvoid Blake2b.MultiPart256.add( BytesStore message );\nvoid Blake2b.MultiPart512.add( BytesStore message );\n----\n\nThe hash for the collection of messages is then obtained as follows:\n[source, Java]\n----\nBytesStore Blake2b.MultiPart256.hash();                   // create a BytesStore to hold the hash\nBytesStore Blake2b.MultiPart256.hash( BytesStore result); // place hash in provided BytesStore\n\nBytesStore Blake2b.MultiPart512.hash();                   // create a BytesStore to hold the hash\nBytesStore Blake2b.MultiPart512.hash( BytesStore result); // place hash in provided BytesStore\n----\n\nOnce `hash` has been called the `MultiPart256` or `MultiPart512` object should not be used further without first\nbeing reset:\n[source, Java]\n----\nvoid Blake2b.MultiPart256.reset();\nvoid Blake2b.MultiPart512.reset();\n----\n\nThe following is a complete example generating the Blake2b-256 and Blake2b-512 hash of a collection of messages:\n[source, Java]\n----\nBytesStore message1 = NativeBytesStore.from( \"abcdefgh\");\nBytesStore message2 = NativeBytesStore.from( \"ijklmnop\");\nBytesStore message3 = NativeBytesStore.from( \"qrstuvwxyz\");\n\n// Initialise a MultiPart256 wrapper\nBlake2b.MultiPart256 multi256 = new Blake2b.MultiPart256();\nmulti256.add( message1 );\nmulti256.add( message2 );\nmulti256.add( message3 );\n\n// Generate the single Blake2b-256 hash of the set of messages\nBytesStore hash256 = multi256.hash();\n\n// Initialise a MultiPart512 wrapper\nBlake2b.MultiPart512 multi512 = new Blake2b.MultiPart512();\nmulti512.add( message1 );\nmulti512.add( message2 );\nmulti512.add( message3 );\n\n// Generate the single Blake2b-512 hash of the set of messages\nBytesStore hash512 = multi512.hash();\n\nSystem.out.println(\"Blake2b 256: \" + DatatypeConverter.printHexBinary(hash256.toByteArray()));\nSystem.out.println(\"Blake2b 512: \" + DatatypeConverter.printHexBinary(hash512.toByteArray()));\n----\n\nThe above prints the following, matching the hashes of the full message `abcdefghijklmnopqrstuvwxyz`:\n[source]\n----\nBlake2b-256: 117AD6B940F5E8292C007D9C7E7350CD33CF85B5887E8DA71C7957830F536E7C\n\nBlake2b-512: C68EDE143E416EB7B4AAAE0D8E48E55DD529EAFED10B1DF1A61416953A2B0A56\n             66C761E7D412E6709E31FFE221B7A7A73908CB95A4D120B8B090A87D1FBEDB4C\n----\n\n== Benchmark\n\nThe library can be run in parallel to improve throughput\n\n.Ed25519 performance\n|===\n| system | sign | verify \n| i7-7700HQ 4 core |  64K/s | 26K/s \n| i7-7820X 8 core | 206K/s | 87K/s\n| E5-2650 v4 24 core | 306K/s | 154K/s\n| E5-2650 v4 24 core, batch | 506K/s | 202K/s\n|===\n\n.SHA-2 performance\n|===\n| system | sha256 of 55 bytes | sha512 of 110 bytes\n| i7-7820X 8 core | 21 M/s | 17 M/s\n| E5-2650 v4 24 core | 39 M/s | 31 M/s\n|===\n\n=== Error message\n\n`java.lang.UnsatisfiedLinkError: net.openhft.chronicle.salt.Bridge.crypto_box_easy(JJJJJJ)I`\nYou need to run `mvn install` to build `libbridge` first.\n\n== Key Terms\n\nChronicle Bytes :: A similar purpose to Java NIO’s ByteBuffer, but with added extenstions.        https://github.com/OpenHFT/Chronicle-Bytes/blob/master/README.adoc[View Chronicle-Bytes here]\n \nCryptography :: The practice of hiding information using a mix of mathematics, computer science and electrical engineering.\n\nDecrypt :: Decoding a message using a public key.\n\nDigital Signature :: A digital code attached to an electronically transmitted document to verify its contents and the senders identity.\n\nEd25519 Signatures :: A public key signature system\n\nHash :: A mathematical algorithm that maps data of arbitrary size, to a bit string of a fixed size (a hash). It is designed to be a one way function i.e. a function which is infeasible to revert.\n\nHexadecimal Dump - To be updated.\n\nLibsodium :: A modern, easy-to-use software library for encryption, decryption, signatures, password hashing and more.\n\nPrivate Key :: A variable used within an algorithm to encrypt and decrypt code. Mathematically linked to a public  key.\n\nPublic Key :: A large numerical value used to encrypt data.\n\nScalability :: The capability of a system, network or process to handle large amounts of work, or its potential to be enlarged to accommodate growth.\n\nSeed :: A number or other value that has been generated by software using one or more values.\n\nThroughput :: The amount of data successfully moved from one place to another in a given timeframe.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenhft%2Fchronicle-salt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fopenhft%2Fchronicle-salt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenhft%2Fchronicle-salt/lists"}