【问题标题】:How can I create or open a libsodium compatible sealed box in pure Java如何在纯 Java 中创建或打开与 libsodium 兼容的密封盒
【发布时间】:2017-07-16 08:19:50
【问题描述】:

libsodium 提供 API 来创建或打开此处记录的密封盒 https://download.libsodium.org/doc/public-key_cryptography/sealed_boxes.html

我如何在纯 Java 中实现相同的功能,以便我可以打开一个由 libsodium 创建的盒子或创建一个 libsodium 可以打开的盒子?

【问题讨论】:

    标签: java encryption public-key-encryption elliptic-curve libsodium


    【解决方案1】:

    以下示例代码可以创建并打开一个 libsodium 密封盒。

    它需要来自https://github.com/InstantWebP2P/tweetnacl-java 的 TweetNaclFast 和一个 Blake2b 哈希实现,例如来自https://github.com/alphazero/Blake2b 的那个

    import java.security.GeneralSecurityException;
    import java.util.Arrays;
    import ove.crypto.digest.Blake2b;
    import com.iwebpp.crypto.TweetNaclFast;
    
    
    /**
     * Example how to open sealed boxes in pure java (libsodium sealed boxes according to 
     * https://download.libsodium.org/doc/public-key_cryptography/sealed_boxes.html)
     * 
     * Has a dependency on TweetNaclFast and Blake2B, for example
     * 
     * https://github.com/alphazero/Blake2b
     * and
     * https://github.com/InstantWebP2P/tweetnacl-java
     * 
     */
    public class SealedBoxUtility {
    
    
    public static final int crypto_box_NONCEBYTES = 24;
    public static final int crypto_box_PUBLICKEYBYTES = 32;
    public static final int crypto_box_MACBYTES = 16;
    public static final int crypto_box_SEALBYTES = (crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES);
    
    //  libsodium
    //  int crypto_box_seal(unsigned char *c, const unsigned char *m,
    //            unsigned long long mlen, const unsigned char *pk);
    
    
    /**
     * Encrypt in  a sealed box
     *
     * @param clearText clear text
     * @param receiverPubKey receiver public key
     * @return encrypted message
     * @throws GeneralSecurityException 
     */
    public static byte[] crypto_box_seal(byte[] clearText, byte[] receiverPubKey) throws GeneralSecurityException {
    
        // create ephemeral keypair for sender
        TweetNaclFast.Box.KeyPair ephkeypair = TweetNaclFast.Box.keyPair();
        // create nonce
        byte[] nonce = crypto_box_seal_nonce(ephkeypair.getPublicKey(), receiverPubKey);
        TweetNaclFast.Box box = new TweetNaclFast.Box(receiverPubKey, ephkeypair.getSecretKey());
        byte[] ciphertext = box.box(clearText, nonce);
        if (ciphertext == null) throw new GeneralSecurityException("could not create box");
    
        byte[] sealedbox = new byte[ciphertext.length + crypto_box_PUBLICKEYBYTES];
        byte[] ephpubkey = ephkeypair.getPublicKey();
        for (int i = 0; i < crypto_box_PUBLICKEYBYTES; i ++)
            sealedbox[i] = ephpubkey[i];
    
        for(int i = 0; i < ciphertext.length; i ++)
            sealedbox[i+crypto_box_PUBLICKEYBYTES]=ciphertext[i];
    
        return sealedbox;
    }
    
    //  libsodium:
    //      int
    //      crypto_box_seal_open(unsigned char *m, const unsigned char *c,
    //                           unsigned long long clen,
    //                           const unsigned char *pk, const unsigned char *sk)
    
    /**
     * Decrypt a sealed box
     *
     * @param c ciphertext
     * @param pk receiver public key
     * @param sk receiver secret key
     * @return decrypted message
     * @throws GeneralSecurityException 
     */
    public static byte[] crypto_box_seal_open( byte[]c, byte[] pk, byte[]sk ) throws GeneralSecurityException{
        if ( c.length < crypto_box_SEALBYTES) throw new IllegalArgumentException("Ciphertext too short");
    
        byte[] pksender = Arrays.copyOfRange(c, 0, crypto_box_PUBLICKEYBYTES);
        byte[] ciphertextwithmac = Arrays.copyOfRange(c, crypto_box_PUBLICKEYBYTES , c.length);
        byte[] nonce = crypto_box_seal_nonce(pksender,pk);
    
        TweetNaclFast.Box box = new TweetNaclFast.Box(pksender, sk);
        byte[] cleartext = box.open(ciphertextwithmac, nonce);
        if (cleartext == null) throw new GeneralSecurityException("could not open box");
        return cleartext;
    }
    
    
    /**
     *  hash the combination of senderpk + mypk into nonce using blake2b hash
     * @param senderpk the senders public key
     * @param mypk my own public key
     * @return the nonce computed using Blake2b generic hash
     */
    public static byte[] crypto_box_seal_nonce(byte[] senderpk, byte[] mypk){
    // C source ported from libsodium
    //      crypto_generichash_state st;
    //
    //      crypto_generichash_init(&st, NULL, 0U, crypto_box_NONCEBYTES);
    //      crypto_generichash_update(&st, pk1, crypto_box_PUBLICKEYBYTES);
    //      crypto_generichash_update(&st, pk2, crypto_box_PUBLICKEYBYTES);
    //      crypto_generichash_final(&st, nonce, crypto_box_NONCEBYTES);
    //
    //      return 0;
        final Blake2b blake2b = Blake2b.Digest.newInstance( crypto_box_NONCEBYTES ); 
        blake2b.update(senderpk);
        blake2b.update(mypk);
        byte[] nonce = blake2b.digest();
        if (nonce == null || nonce.length!=crypto_box_NONCEBYTES) throw new IllegalArgumentException("Blake2b hashing failed");
        return nonce;
    
    
    }
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-20
      • 1970-01-01
      • 2018-09-13
      • 2014-07-20
      • 2017-04-21
      • 2016-04-01
      相关资源
      最近更新 更多