package com.iwebpp.crypto.tests;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import android.util.Log;
import com.iwebpp.crypto.TweetNaclFast;
public final class TweetNaclFastTest {
private static final String TAG = "TweetNaclFastTest";
/**
* Curve25519 test vectors to help ensure correctness and interoperability
* copied from Kalium project (https://github.com/abstractj/kalium)
*/
public static final String BOB_PRIVATE_KEY = "5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb";
public static final String BOB_PUBLIC_KEY = "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f";
public static final String ALICE_PRIVATE_KEY = "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a";
public static final String ALICE_PUBLIC_KEY = "8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a";
public static final String ALICE_MULT_BOB = "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742";
public static final String BOX_NONCE = "69696ee955b62b73cd62bda875fc73d68219e0036b7a0b37";
public static final String BOX_MESSAGE = "be075fc53c81f2d5cf141316ebeb0c7b5228c52a4c62cbd44b66849b64244ffc" +
"e5ecbaaf33bd751a1ac728d45e6c61296cdc3c01233561f41db66cce314adb31" +
"0e3be8250c46f06dceea3a7fa1348057e2f6556ad6b1318a024a838f21af1fde" +
"048977eb48f59ffd4924ca1c60902e52f0a089bc76897040e082f93776384864" +
"5e0705";
public static final String BOX_CIPHERTEXT = "f3ffc7703f9400e52a7dfb4b3d3305d98e993b9f48681273c29650ba32fc76ce" +
"48332ea7164d96a4476fb8c531a1186ac0dfc17c98dce87b4da7f011ec48c972" +
"71d2c20f9b928fe2270d6fb863d51738b48eeee314a7cc8ab932164548e526ae" +
"90224368517acfeabd6bb3732bc0e9da99832b61ca01b6de56244a9e88d5f9b3" +
"7973f622a43d14a6599b1f654cb45a74e355a5";
public static final String SECRET_KEY = "1b27556473e985d462cd51197a9a46c76009549eac6474f206c4ee0844f68389";
public static final String SIGN_PRIVATE = "b18e1d0045995ec3d010c387ccfeb984d783af8fbb0f40fa7db126d889f6dadd";
public static final String SIGN_MESSAGE = "916c7d1d268fc0e77c1bef238432573c39be577bbea0998936add2b50a653171" +
"ce18a542b0b7f96c1691a3be6031522894a8634183eda38798a0c5d5d79fbd01" +
"dd04a8646d71873b77b221998a81922d8105f892316369d5224c9983372d2313" +
"c6b1f4556ea26ba49d46e8b561e0fc76633ac9766e68e21fba7edca93c4c7460" +
"376d7f3ac22ff372c18f613f2ae2e856af40";
public static final String SIGN_SIGNATURE = "6bd710a368c1249923fc7a1610747403040f0cc30815a00f9ff548a896bbda0b" +
"4eb2ca19ebcf917f0f34200a9edbad3901b64ab09cc5ef7b9bcc3c40c0ff7509";
public static final String SIGN_PUBLIC = "77f48b59caeda77751ed138b0ec667ff50f8768c25d48309a8f386a2bad187fb";
private boolean testBoxKalium() throws UnsupportedEncodingException {
Log.d(TAG, "testBoxKalium: test vectors from Kalium project");
// explicit nonce
byte [] theNonce = TweetNaclFast.hexDecode(BOX_NONCE);
Log.d(TAG, "BOX_NONCE: " + "\"" + TweetNaclFast.hexEncodeToString(theNonce) + "\"");
// keypair A
byte [] ska = TweetNaclFast.hexDecode(ALICE_PRIVATE_KEY);
TweetNaclFast.Box.KeyPair ka = TweetNaclFast.Box.keyPair_fromSecretKey(ska);
Log.d(TAG, "ska: " + "\"" + TweetNaclFast.hexEncodeToString(ka.getSecretKey()) + "\"");
Log.d(TAG, "pka: " + "\"" + TweetNaclFast.hexEncodeToString(ka.getPublicKey()) + "\"");
// keypair B
byte [] skb = TweetNaclFast.hexDecode(BOB_PRIVATE_KEY);
TweetNaclFast.Box.KeyPair kb = TweetNaclFast.Box.keyPair_fromSecretKey(skb);
Log.d(TAG, "skb: " + "\"" + TweetNaclFast.hexEncodeToString(kb.getSecretKey()) + "\"");
Log.d(TAG, "pkb: " + "\"" + TweetNaclFast.hexEncodeToString(kb.getPublicKey()) + "\"");
// peer A -> B
TweetNaclFast.Box pabFast = new TweetNaclFast.Box(kb.getPublicKey(), ka.getSecretKey());
// peer B -> A
TweetNaclFast.Box pbaFast = new TweetNaclFast.Box(ka.getPublicKey(), kb.getSecretKey());
// messages
Log.d(TAG, "BOX_MESSAGE: \n" + BOX_MESSAGE.toUpperCase());
Log.d(TAG, "BOX_CIPHERTEXT: \n" + BOX_CIPHERTEXT.toUpperCase());
// cipher A -> B
byte [] cabFast = pabFast.box(TweetNaclFast.hexDecode(BOX_MESSAGE), theNonce);
Log.d(TAG, "cabFast: \n" + TweetNaclFast.hexEncodeToString(cabFast));
if(BOX_CIPHERTEXT.toUpperCase().equals(TweetNaclFast.hexEncodeToString(cabFast))) {
Log.d(TAG, "\n TweetNaclFast is compatible with Kalium test vector for Box::box");
} else {
Log.d(TAG, "\n\n!!! TweetNaclFast Box::box/open failed Kalium compatibility !!!\n");
return false;
}
byte [] mbaFastFast = pbaFast.open(cabFast, theNonce);
Log.d(TAG, "mbaFastFast: \n" + TweetNaclFast.hexEncodeToString(mbaFastFast));
if(BOX_MESSAGE.toUpperCase().equals(TweetNaclFast.hexEncodeToString(mbaFastFast))) {
Log.d(TAG, "\n TweetNaclFast is compatible with Kalium test vector for Box::open");
} else {
Log.d(TAG, "\n\n!!! TweetNaclFast Box::box/open failed Kalium compatibility !!!\n");
return false;
}
return true;
}
private boolean testBox() throws UnsupportedEncodingException {
// keypair A
byte [] ska = new byte[32]; for (int i = 0; i < 32; i ++) ska[i] = 0;
TweetNaclFast.Box.KeyPair ka = TweetNaclFast.Box.keyPair_fromSecretKey(ska);
String skat = "";
for (int i = 0; i < ka.getSecretKey().length; i ++)
skat += " "+ka.getSecretKey()[i];
Log.d(TAG, "skat: "+skat);
String pkat = "";
for (int i = 0; i < ka.getPublicKey().length; i ++)
pkat += " "+ka.getPublicKey()[i];
Log.d(TAG, "pkat: "+pkat);
// keypair B
byte [] skb = new byte[32]; for (int i = 0; i < 32; i ++) skb[i] = 1;
TweetNaclFast.Box.KeyPair kb = TweetNaclFast.Box.keyPair_fromSecretKey(skb);
String skbt = "";
for (int i = 0; i < kb.getSecretKey().length; i ++)
skbt += " "+kb.getSecretKey()[i];
Log.d(TAG, "skbt: "+skbt);
String pkbt = "";
for (int i = 0; i < kb.getPublicKey().length; i ++)
pkbt += " "+kb.getPublicKey()[i];
Log.d(TAG, "pkbt: "+pkbt);
// peer A -> B
TweetNaclFast.Box pab = new TweetNaclFast.Box(kb.getPublicKey(), ka.getSecretKey(), 0);
// peer B -> A
TweetNaclFast.Box pba = new TweetNaclFast.Box(ka.getPublicKey(), kb.getSecretKey(), 0);
// messages
String m0 = "Helloword, Am Tom ...";
// cipher A -> B
byte [] cab = pab.box(m0.getBytes("utf-8"));
String cabt = "";
for (int i = 0; i < cab.length; i ++)
cabt += " "+cab[i];
Log.d(TAG, "cabt: "+cabt);
byte [] mba = pba.open(cab);
String mbat = "";
for (int i = 0; i < mba.length; i ++)
mbat += " "+mba[i];
Log.d(TAG, "mbat: "+mbat);
String nm0 = new String(mba, "utf-8");
if (nm0.equals(m0)) {
Log.d(TAG, "box/open string success @" + m0);
} else {
Log.e(TAG, "box/open string failed @" + m0 + " / " + nm0);
}
// cipher B -> A
byte [] b0 = new byte[6];
Log.d(TAG, "box@" + System.currentTimeMillis());
byte [] cba = pba.box(b0);
byte [] mab = pab.open(cba);
Log.d(TAG, "open@" + System.currentTimeMillis());
if (b0.length == mab.length) {
int rc = 0;
for (int i = 0; i < b0.length; i ++)
if (!(b0[i] == mab[i])) {
rc = -1;
Log.e(TAG, "box/open binary failed @" + b0[i] + " / " + mab[i]);
}
if (rc == 0)
Log.d(TAG, "box/open binary success @" + b0);
} else {
Log.e(TAG, "box/open binary failed @" + b0 + " / " + mab);
}
return true;
}
private boolean testBoxNonce() throws UnsupportedEncodingException {
// explicit nonce
byte [] theNonce = TweetNaclFast.makeBoxNonce();
byte [] theNonce2 = TweetNaclFast.base64Decode(
TweetNaclFast.base64EncodeToString(theNonce));
Log.d(TAG, "BoxNonce Base64 test Equal: " + "\"" + java.util.Arrays.equals(theNonce, theNonce2) + "\"");
byte [] theNonce3 = TweetNaclFast.hexDecode(
TweetNaclFast.hexEncodeToString(theNonce));
Log.d(TAG, "BoxNonce Hex test Equal: " + "\"" + java.util.Arrays.equals(theNonce, theNonce3) + "\"");
String theNoncet = "";
for (int i = 0; i < theNonce.length; i ++)
theNoncet += " "+theNonce[i];
Log.d(TAG, "BoxNonce: "+theNoncet);
Log.d(TAG, "BoxNonce: " + "\"" + TweetNaclFast.base64EncodeToString(theNonce) + "\"");
Log.d(TAG, "BoxNonce: " + "\"" + TweetNaclFast.hexEncodeToString(theNonce) + "\"");
// keypair A
byte [] ska = new byte[32]; for (int i = 0; i < 32; i ++) ska[i] = 0;
TweetNaclFast.Box.KeyPair ka = TweetNaclFast.Box.keyPair_fromSecretKey(ska);
String skat = "";
for (int i = 0; i < ka.getSecretKey().length; i ++)
skat += " "+ka.getSecretKey()[i];
Log.d(TAG, "skat: "+skat);
String pkat = "";
for (int i = 0; i < ka.getPublicKey().length; i ++)
pkat += " "+ka.getPublicKey()[i];
Log.d(TAG, "pkat: "+pkat);
// keypair B
byte [] skb = new byte[32]; for (int i = 0; i < 32; i ++) skb[i] = 1;
TweetNaclFast.Box.KeyPair kb = TweetNaclFast.Box.keyPair_fromSecretKey(skb);
String skbt = "";
for (int i = 0; i < kb.getSecretKey().length; i ++)
skbt += " "+kb.getSecretKey()[i];
Log.d(TAG, "skbt: "+skbt);
String pkbt = "";
for (int i = 0; i < kb.getPublicKey().length; i ++)
pkbt += " "+kb.getPublicKey()[i];
Log.d(TAG, "pkbt: "+pkbt);
// peer A -> B
TweetNaclFast.Box pab = new TweetNaclFast.Box(kb.getPublicKey(), ka.getSecretKey());
// peer B -> A
TweetNaclFast.Box pba = new TweetNaclFast.Box(ka.getPublicKey(), kb.getSecretKey());
// messages
String m0 = "Helloword, Am Tom ...";
// cipher A -> B
byte [] cab = pab.box(m0.getBytes("utf-8"), theNonce);
String cabt = "";
for (int i = 0; i < cab.length; i ++)
cabt += " "+cab[i];
Log.d(TAG, "cabt: "+cabt);
byte [] mba = pba.open(cab, theNonce);
String mbat = "";
for (int i = 0; i < mba.length; i ++)
mbat += " "+mba[i];
Log.d(TAG, "mbat: "+mbat);
String nm0 = new String(mba, "utf-8");
if (nm0.equals(m0)) {
Log.d(TAG, "box/open string success (with nonce) @" + m0);
} else {
Log.e(TAG, "box/open string failed (with nonce) @" + m0 + " / " + nm0);
}
// cipher B -> A
byte [] b0 = new byte[6];
Log.d(TAG, "box@" + System.currentTimeMillis());
byte [] cba = pba.box(b0, theNonce);
byte [] mab = pab.open(cba, theNonce);
Log.d(TAG, "open@" + System.currentTimeMillis());
if (b0.length == mab.length) {
int rc = 0;
for (int i = 0; i < b0.length; i ++)
if (!(b0[i] == mab[i])) {
rc = -1;
Log.e(TAG, "box/open binary failed (with nonce) @" + b0[i] + " / " + mab[i]);
}
if (rc == 0)
Log.d(TAG, "box/open binary success (with nonce) @" + b0);
} else {
Log.e(TAG, "box/open binary failed (with nonce) @" + b0 + " / " + mab);
}
return true;
}
private boolean testSecretBox() throws UnsupportedEncodingException {
// shared key
byte [] shk = new byte[TweetNaclFast.SecretBox.keyLength];
for (int i = 0; i < shk.length; i ++)
shk[i] = 0x66;
// peer A -> B
TweetNaclFast.SecretBox pab = new TweetNaclFast.SecretBox(shk, 0);
// peer B -> A
TweetNaclFast.SecretBox pba = new TweetNaclFast.SecretBox(shk, 0);
// messages
String m0 = "Helloword, Am Tom ...";
// cipher A -> B
Log.d(TAG, "streess on secret box@"+m0);
for (int t = 0; t < 19; t ++, m0 += m0) {
byte [] mb0 = m0.getBytes("utf-8");
Log.d(TAG, "\n\n\tstreess/"+(mb0.length/1000.0) +"kB: " + t + " times");
/*String mb0t = "mb0/"+mb0.length + ": ";
for (int i = 0; i < mb0.length; i ++)
mb0t += " "+mb0[i];
Log.d(TAG, mb0t);
*/
Log.d(TAG, "secret box ...@" + System.currentTimeMillis());
byte [] cab = pab.box(mb0);
Log.d(TAG, "... secret box@" + System.currentTimeMillis());
/*String cabt = "cab/"+cab.length + ": ";
for (int i = 0; i < cab.length; i ++)
cabt += " "+cab[i];
Log.d(TAG, cabt);
*/
Log.d(TAG, "\nsecret box open ...@" + System.currentTimeMillis());
byte [] mba = pba.open(cab);
Log.d(TAG, "... secret box open@" + System.currentTimeMillis());
/*
String mbat = "mba/"+mba.length + ": ";
for (int i = 0; i < mba.length; i ++)
mbat += " "+mba[i];
Log.d(TAG, mbat);
*/
String nm0 = new String(mba, "utf-8");
if (nm0.equals(m0)) {
Log.d(TAG, "\tsecret box/open succes");
} else {
Log.e(TAG, "\tsecret box/open failed @" + m0 + " / " + nm0);
return false;
}
}
return true;
}
private boolean testSecretBoxNonce() throws UnsupportedEncodingException {
// explicit nonce
byte [] theNonce = TweetNaclFast.makeSecretBoxNonce();
String theNoncet = "";
for (int i = 0; i < theNonce.length; i ++)
theNoncet += " "+theNonce[i];
Log.d(TAG, "SecretBoxNonce: "+theNoncet);
// shared key
byte [] shk = new byte[TweetNaclFast.SecretBox.keyLength];
for (int i = 0; i < shk.length; i ++)
shk[i] = 0x66;
// peer A -> B
TweetNaclFast.SecretBox pab = new TweetNaclFast.SecretBox(shk);
// peer B -> A
TweetNaclFast.SecretBox pba = new TweetNaclFast.SecretBox(shk);
// messages
String m0 = "Helloword, Am Tom ...";
// cipher A -> B
Log.d(TAG, "stress on secret box with explicit nonce@"+m0);
for (int t = 0; t < 19; t ++, m0 += m0) {
byte [] mb0 = m0.getBytes("utf-8");
Log.d(TAG, "\n\n\tstress/"+(mb0.length/1000.0) +"kB: " + t + " times");
/*String mb0t = "mb0/"+mb0.length + ": ";
for (int i = 0; i < mb0.length; i ++)
mb0t += " "+mb0[i];
Log.d(TAG, mb0t);
*/
Log.d(TAG, "secret box ...@" + System.currentTimeMillis());
byte [] cab = pab.box(mb0, theNonce);
Log.d(TAG, "... secret box@" + System.currentTimeMillis());
/*String cabt = "cab/"+cab.length + ": ";
for (int i = 0; i < cab.length; i ++)
cabt += " "+cab[i];
Log.d(TAG, cabt);
*/
Log.d(TAG, "\nsecret box open ...@" + System.currentTimeMillis());
byte [] mba = pba.open(cab, theNonce);
Log.d(TAG, "... secret box open@" + System.currentTimeMillis());
/*
String mbat = "mba/"+mba.length + ": ";
for (int i = 0; i < mba.length; i ++)
mbat += " "+mba[i];
Log.d(TAG, mbat);
*/
String nm0 = new String(mba, "utf-8");
if (nm0.equals(m0)) {
Log.d(TAG, "\tsecret box/open succes (with nonce)");
} else {
Log.e(TAG, "\tsecret box/open failed (with nonce) @" + m0 + " / " + nm0);
return false;
}
}
return true;
}
private boolean testSign() throws UnsupportedEncodingException {
// keypair A
TweetNaclFast.Signature.KeyPair ka = TweetNaclFast.Signature.keyPair();
// keypair B
TweetNaclFast.Signature.KeyPair kb = TweetNaclFast.Signature.keyPair();
// peer A -> B
TweetNaclFast.Signature pab = new TweetNaclFast.Signature(kb.getPublicKey(), ka.getSecretKey());
// peer B -> A
TweetNaclFast.Signature pba = new TweetNaclFast.Signature(ka.getPublicKey(), kb.getSecretKey());
// messages
String m0 = "Helloword, Am Tom ...";
// signature A -> B
Log.d(TAG, "\nsign...@" + System.currentTimeMillis());
byte [] sab = pab.sign(m0.getBytes("utf-8"));
Log.d(TAG, "...sign@" + System.currentTimeMillis());
String sgt = "sign@"+m0 + ": ";
for (int i = 0; i < TweetNaclFast.Signature.signatureLength; i ++)
sgt += " "+sab[i];
Log.d(TAG, sgt);
Log.d(TAG, "verify...@" + System.currentTimeMillis());
byte [] oba = pba.open(sab);
Log.d(TAG, "...verify@" + System.currentTimeMillis());
if (oba == null) {
Log.e(TAG, "verify failed @" + m0);
} else {
String nm0 = new String(oba, "utf-8");
if (nm0.equals(m0)) {
Log.d(TAG, "sign success @" + m0);
} else {
Log.e(TAG, "sign failed @" + m0 + " / " + nm0);
}
}
// keypair C
byte [] seed = new byte[TweetNaclFast.Signature.seedLength]; for (int i = 0; i < seed.length; i ++) seed[i] = 0x66;
TweetNaclFast.Signature.KeyPair kc = TweetNaclFast.Signature.keyPair_fromSeed(seed);
String skct = "";
for (int i = 0; i < kc.getSecretKey().length; i ++)
skct += " "+kc.getSecretKey()[i];
Log.d(TAG, "skct: "+skct);
String pkct = "";
for (int i = 0; i < kc.getPublicKey().length; i ++)
pkct += " "+kc.getPublicKey()[i];
Log.d(TAG, "pkct: "+pkct);
// self-signed
TweetNaclFast.Signature pcc = new TweetNaclFast.Signature(kc.getPublicKey(), kc.getSecretKey());
Log.d(TAG, "\nself-sign...@" + System.currentTimeMillis());
byte [] scc = pcc.sign(m0.getBytes("utf-8"));
Log.d(TAG, "...self-sign@" + System.currentTimeMillis());
String ssc = "self-sign@"+m0 + ": ";
for (int i = 0; i < TweetNaclFast.Signature.signatureLength; i ++)
ssc += " "+scc[i];
Log.d(TAG, ssc);
Log.d(TAG, "self-verify...@" + System.currentTimeMillis());
byte [] occ = pcc.open(scc);
Log.d(TAG, "...self-verify@" + System.currentTimeMillis());
if (occ == null) {
Log.e(TAG, "self-verify failed @" + m0);
} else {
String nm0 = new String(occ, "utf-8");
if (nm0.equals(m0)) {
Log.d(TAG, "self-sign success @" + m0);
} else {
Log.e(TAG, "self-sign failed @" + m0 + " / " + nm0);
}
}
return true;
}
/*
* SHA-512
* */
private boolean testHash() throws UnsupportedEncodingException {
String m0 = "Helloword, Am Tom ...";
byte [] b0 = m0.getBytes("utf-8");
Log.d(TAG, "\nsha512...@" + System.currentTimeMillis());
byte [] hash = TweetNaclFast.Hash.sha512(b0);
Log.d(TAG, "...sha512@" + System.currentTimeMillis());
String hst = "sha512@"+m0 + "/"+b0.length + ": ";
for (int i = 0; i < hash.length; i ++)
hst += " "+hash[i];
Log.d(TAG, hst);
return true;
}
/*
* bench test using tweetnacl.c, tweetnacl.js result
* */
private boolean testBench() {
return true;
}
public void start() {
(new Thread(new Runnable() {
public void run() {
Log.d(TAG, "start test");
try {
testSecretBox();
testSecretBoxNonce();
testBox();
testBoxNonce();
testBoxKalium();
testHash();
testSign();
///testBench();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
})).start();
}
public static void main(String[] args) {
TweetNaclFastTest t = new TweetNaclFastTest();
t.start();
}
}