GithubHelp home page GithubHelp logo

instantwebp2p / tweetnacl-java Goto Github PK

View Code? Open in Web Editor NEW
43.0 6.0 28.0 266 KB

TweetNaCl in Java - a port of TweetNaCl-js

Home Page: https://instantwebp2p.github.io/tweetnacl-java

License: MIT License

Makefile 0.03% JavaScript 31.27% C++ 0.66% Java 56.63% C 11.21% Kotlin 0.12% Shell 0.07%
cryptographic tweetnacl nacl

tweetnacl-java's Introduction

TweetNacl in Java: port of tweetnacl-js

Java CI

Download

Using Gradle

implementation "io.github.instantwebp2p:tweetnacl-java:1.1.2"

API/Usage

Suggest always use TweetNaclFast implementation

Public key authenticated encryption

  • get key pair: Box.KeyPair kp = Box.keyPair(), kp = Box.keyPair_fromSecretKey(sk)
  • new Box object: Box box = new Box(theirPublicKey, mySecretKey, Nonce);
  • encryption: cipher = box.box(message);
  • decryption: message = box.open(cipher);
  • Nonce MUST be unique for ever message passed between same peers

As an alternative, the nonce can be omitted from the Box() call, and passed in the box and open calls, like:

  • byte [] nonce = new byte[nonceLength], randombytes(theNonce, nonceLength);
  • Box.KeyPair kp = Box.keyPair(), kp = Box.keyPair_fromSecretKey(sk)
  • Box box = new Box(theirPublicKey, mySecretKey);
  • encryption: cipher = box.box(message, nonce);
  • decryption: message = box.open(cipher, nonce);

Secret key authenticated encryption

  • get shared key: crypto random, what you have
  • new SecretBox object: SecretBox sbox = new SecretBox(sharedKey, Nonce);
  • encryption: cipher = sbox.box(message);
  • decryption: message = sbox.open(cipher);
  • Nonce MUST be unique for ever message passed between same peers

As an alternative, the nonce can be omitted from the SecretBox() call, and passed in the box and open calls, like:

  • byte [] nonce = new byte[nonceLength], randombytes(theNonce, nonceLength);
  • SecretBox sbox = new SecretBox(sharedKey);
  • cipher = sbox.box(message, nonce);
  • decryption: message = sbox.open(cipher, nonce);

Signature

  • get key pair: Signature.KeyPair kp = Signature.keyPair(), kp = Signature.keyPair_fromSecretKey(sk);
  • new Signature object: Signature sig = new Signature(theirPublicKey, mySecretKey);
  • sign: signedMessage = sig.sign(message);
  • verify: message = sig.open(signedMessage);
  • Nonce MUST be unique for ever message passed between same peers

Hash

  • generate SHA-512: byte [] tag = Hash.sha512(message);

Refer to com.iwebpp.crypto.tests for details

About Random generation

  • the library uses java.security.SecureRandom for key generation
  • you can always use the library to generate key, or use a Crypto Random like java.security.SecureRandom

Testing

In top directory:

$ mvn test

Support us

  • Welcome contributing on document, codes, tests and issues

License MIT

tweetnacl-java's People

Contributors

andsdev avatar dependabot[bot] avatar eontechnology avatar eygraber avatar franks42 avatar furygo avatar sequoiar avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

tweetnacl-java's Issues

[BUG] A defect in function `crypto_sign_open`

I used to invoke function crypto_sign_open which in TweetNacl.java and had never verified successfully.
How I write a process is follows:

    TweetNacl.Signature signObj = new TweetNacl.Signature(Base58Utils.decode(pubKey), new byte[0]);
    return signObj.detached_verify(signMessage.getBytes(StandardCharsets.UTF_8), Base58Utils.decode(signature));

Then i found that there is a bug in the function vn:

    private static int vn(
            byte [] x, final int xoff, final int xlen,
            byte [] y, final int yoff, final int ylen,
            int n)
    {
        int i,d = 0;
        for (i = 0; i < n; i ++) {
            d |= (x[i+xoff]^y[i+yoff]) & 0xff;
        }
        return (1 & ((d - 1) >>> 8)) - 1;
    }

which should be modified to:

    private static int vn(
            byte [] x, final int xoff, final int xlen,
            byte [] y, final int yoff, final int ylen,
            int n)
    {
        byte[] d = new byte[1];
        for (int i = 0; i < n; i ++) d[0] |= (x[i+xoff]^y[i+yoff]);
        return (1 & ((d[0] - 1) >>> 8)) - 1;
    }

Insecure PRNG

tweetnacl-java uses java.util.Random which is not a CPRNG and thus is not suitable for cryptographic applications because it can be easily predicted. java.security.SecureRandom is CPRNG that is generally available on JVMs.

running the tests "easily"

Hi Tom - thanks for the tweetnacl port - great work!!!

Not sure how you run the java tests in TweetNaclTest and TweetNaclFastTest...
I've added to TweetNaclTest.java:

public static void main(String[] args) {
    TweetNaclTest t = new TweetNaclTest();
    t.start();
}

and similar lines to the TweetNaclFastTest.java.

Then run the following from the command line in top directory:

$ mkdir out
$ javac -d out src/com/iwebpp/crypto/TweetNacl.java src/com/iwebpp/crypto/TweetNaclFast.java src/com/iwebpp/crypto/tests/TweetNaclTest.java src/com/iwebpp/crypto/tests/TweetNaclFastTest.java src/com/iwebpp/crypto/tests/Log.java
$ java -cp out com.iwebpp.crypto.tests.TweetNaclTest
$ java -cp out com.iwebpp.crypto.tests.TweetNaclFastTest

Want to add those few lines to the TweetNaclTest.java, TweetNaclFastTest.java and the readme?

Use of nonce in class Box is unclear

Trying to understand how that nonce is used in the "Box" class code, and I'm "puzzled".

As I understand the use of the nonce, Alice has to generate that unique nonce that is used inside Box's "box" method in the "crypto_box" C-call, and that same non-secret nonce has to be communicated to Bob, who will use it inside of Box's "open" method to decrypt in the "crypto_box_open" C-call. The nonce is used in addition to the shared secret or the private keys, and the difference is that it is not a secret and should be uniquely tied to the encrypted message.

However, the only way to (optionally) pass a nonce in, is through the Box constructor, but there seems to be no way to get that nonce value out. How does Alice communicate the used nonce to Bob?

Also, the nonce value passed-in is a java-long, which has to be converted to a byte[], which is tricky if you have to communicate values between different languages and CPUs. (the C-implementation seems to work with char arrays only (?), while the example code in bench.cpp prepares a nonce value that is passed to both the crypto_secretbox() and crypto_secretbox_open())

If I compare it to the Kalium code, then the nonce is passed in the encrypt and decrypt methods of the Kalium's Box class explicitly (as byte[]), which seem to map to tweet-nacl-java's Box's "box" and "open" call.

It's not easy to follow the correct flow in the code, and I may very well be missing something... but right now it feels to me that the nonce may be used incorrectly.

Could you create a new tag?

Would it be possible to throw a 1.1.2 tag at the current master?

I'd like to use a tagged implementation, but 1.1.1 was from 2015, and it looks like there have been commits since then.

Randomly brings infinit loop

Hi !
I'm trying to bring a JS software to java using this lib and I don't know much about all the theory and crypto things it use.

I quite often (1 over 2 try) run into infinite loop while calling:
public static int crypto_secretbox(byte [] c, byte [] m, int /long/ d, byte [] n, byte [] k);

When such infinit loop may occur ?
Would a unit test showing the call with params and the infinit loop in action help ?
Many thanks for your help

Compatibility between TweetNacl and TweetNaclFast for Box?

As I understand it, the "Fast" version pre-calculates the DH shared-key and uses that directly for the encryption&signing.
I expected the output from the box() method on the TweetNacl.Box and the TweetNaclFast.Box instances to be compatible, i.e. have the same encrypted message and format, and be interchangeable.

However, I get errors if I mix them up, like in TweetNaclFastTest.java, I added

           import com.iwebpp.crypto.TweetNacl;

and added to the Box test case:

    // peer A -> B
    TweetNaclFast.Box pab = new TweetNaclFast.Box(kb.getPublicKey(), ka.getSecretKey());
    //TweetNacl.Box pab = new TweetNacl.Box(kb.getPublicKey(), ka.getSecretKey());

    // peer B -> A
    TweetNaclFast.Box pba = new TweetNaclFast.Box(ka.getPublicKey(), kb.getSecretKey());
    //TweetNacl.Box pba = new TweetNacl.Box(ka.getPublicKey(), kb.getSecretKey());

If they are compatible, I can mix and match the two classes - uncomment one and comment the other.
However, I get null pointers when I do that.
All ok when I box() and open() with the same version.

Is that a bug? Do I miss anything?

Use of nonce in class Box is unclear

Trying to understand how that nonce is used in the "Box" class code, and I'm "puzzled".

As I understand the use of the nonce, Alice has to generate that unique nonce that is used inside Box's "box" method in the "crypto_box" call, and that same non-secret nonce has to be communicated to Bob, who will use it inside of Box's "open" method to decrypt in the "crypto_box_open" call. The nonce is used in addition to the shared secret or the private keys, and the difference is that it is not a secret and should be uniquely tied to the encrypted message.

However, the only way to (optionally) pass a nonce in, is through the Box constructor, but there seems to be no way to get that nonce value out. How does Alice communicate the used nonce to Bob?

Also, the nonce value passed-in is a java-long, which has to be converted to a byte[], which is tricky if you have to communicate values between different languages and CPUs. (the C-implementation seems to work with char arrays only (?), while the example code in bench.cpp prepares a nonce value that is passed to both the crypto_secretbox() and crypto_secretbox_open())

If I compare it to the Kalium code, then the nonce is passed in the encrypt and decrypt methods of the Kalium's Box class explicitly (as byte[]), which seem to map to tweet-nacl-java's Box's "box" and "open" call.

It's not easy to follow the correct flow in the code, and I may very well be missing something... but right now it feels to me that the nonce may be used incorrectly.

keyPair_fromSeed() is insecure/misleading

public static KeyPair keyPair_fromSeed(byte [] seed) simply takes the seed and uses it as the secret key. This is horribly insecure, because seeds are usually of very little entropy and very predictable.

Therefore, we should either rename the function to something like "keyPair_fromSecretKey(byte[] secretKey)",

OR

make it handle the seed correctly, for example by seeding SecureRandom with "seed" and then taking "sk" from it, like so:

public static int crypto_box_keypair_with_seed(byte[] pk, byte[] sk, byte[] seed)
{
    // create secret key randomly (default RNG of current platform)
    SecureRandom rng = new SecureRandom();
    byte[] random = new byte[crypto_secretbox_SECRETKEYBYTES];
    rng.nextBytes(random);
    
    // create more or less random number from seed
    SecureRandom rngSeeded = SecureRandom.getInstance("SHA1PRNG");
    rngSeeded.setSeed(seed);
    byte[] randomSeeded = new byte[crypto_secretbox_SECRETKEYBYTES];
    rngSeeded.nextBytes(randomSeeded);

    // XOR the two random numbers, forming the secret key
    for (byte b : random) {
        sk[i] = b ^ randomSeeded[i++];
    }
    
    return curve25519.crypto_scalarmult_base(pk, sk);
} 

PS: excuse me for taking this example from jNaCl.

This actually creates "random" randomly (default PRNG), then seeds the SHA1-PRNG with "seed" and gets a second random number "randomSeeded", finally XORing "random" and "randomSeeded" together, to form "sk". This was done because the default PRNG is sometimes better than SHA1-PRNG, sometimes worse, but in any case should we never solely rely on a deterministic seeding of the SHA1-PRNG. SHA1 was chosen, however, because it is widely believed to be secure, IF the seed is not compromised. By combining both methods (via XOR), we hopefully get the best of both worlds.

What do you think of this?
Cheers

Not published as a jar

Why isn't this library published to maven central? As it stands it's roughly impossible for people to adopt.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.