Data security in mobile Java applications

Learn how to select and use third-party security toolkits

1 2 3 4 Page 3
Page 3 of 4
BigInteger mod = RSAprivKey.getModulus();
out = new FileOutputStream(outdir + "RSAmod.dat");
out.write(mod.toByteArray());
out.flush();
out.close();
BigInteger privExp = RSAprivKey.getExponent();
out = new FileOutputStream(outdir + "RSAprivExp.dat");
out.write(privExp.toByteArray());
out.flush();
out.close();
pubExp = RSAprivKey.getPublicExponent();
if ( !pubExp.equals(new BigInteger("10001", 16)) )
  throw new Exception("public exponent does not match");
out = new FileOutputStream(outdir + "RSApubExp.dat");
out.write(pubExp.toByteArray());
out.flush();
out.close();
BigInteger dp = RSAprivKey.getDP();
out = new FileOutputStream(outdir + "RSAdp.dat");
out.write(dp.toByteArray());
out.flush();
out.close();
BigInteger dq = RSAprivKey.getDQ();
out = new FileOutputStream(outdir + "RSAdq.dat");
out.write(dq.toByteArray());
out.flush();
out.close();
BigInteger p = RSAprivKey.getP();
out = new FileOutputStream(outdir + "RSAp.dat");
out.write(p.toByteArray());
out.flush();
out.close();
BigInteger q = RSAprivKey.getQ();
out = new FileOutputStream(outdir + "RSAq.dat");
out.write(q.toByteArray());
out.flush();
out.close();
BigInteger qInv = RSAprivKey.getQInv();
out = new FileOutputStream(outdir + "RSAqInv.dat");
out.write(qInv.toByteArray());
out.flush();
out.close();

Among those parameters, mod and pubExp are needed for reconstructing the public key. To reconstruct public and private keys from serialized parameters, we use the following code in CryptoEngine's constructor:

Listing 3. Reconstruct key pair in CryptoEngine's constructor

is = c.getResourceAsStream("/keys/RSAmod.dat");
BigInteger RSAmod = new BigInteger(readFromStream(is));
is.close();
is = c.getResourceAsStream("/keys/RSAprivExp.dat");
BigInteger RSAprivExp = new BigInteger(readFromStream(is));
is.close();
is = c.getResourceAsStream("/keys/RSApubExp.dat");
BigInteger RSApubExp = new BigInteger(readFromStream(is));
is.close();
is = c.getResourceAsStream("/keys/RSAdp.dat");
BigInteger RSAdp = new BigInteger(readFromStream(is));
is.close();
is = c.getResourceAsStream("/keys/RSAdq.dat");
BigInteger RSAdq = new BigInteger(readFromStream(is));
is.close();
is = c.getResourceAsStream("/keys/RSAp.dat");
BigInteger RSAp = new BigInteger(readFromStream(is));
is.close();
is = c.getResourceAsStream("/keys/RSAq.dat");
BigInteger RSAq = new BigInteger(readFromStream(is));
is.close();
is = c.getResourceAsStream("/keys/RSAqInv.dat");
BigInteger RSAqInv = new BigInteger(readFromStream(is));
is.close();
RSAprivKey = new RSAPrivateCrtKeyParameters(RSAmod, RSApubExp,
                  RSAprivExp, RSAp, RSAq, RSAdp, RSAdq, RSAqInv);
RSApubKey = new RSAKeyParameters(false, RSAmod, RSApubExp);

Once you have keys, signing the digest is simple. Here we use SHA-1 digest:

Listing 4. Bouncy Castle RSA signature generation in CryptoEngine

public byte [] RSASign (byte [] toSign) throws Exception {
  if (RSAprivKey == null)
    throw new Exception("Generate RSA keys first!");
  SHA1Digest dig = new SHA1Digest();
  RSAEngine eng = new RSAEngine();
  PSSSigner signer = new PSSSigner(eng, dig, 64);
  signer.init(true, RSAprivKey);
  signer.update(toSign, 0, toSign.length);
  return signer.generateSignature();
}

The receiving party must have prior knowledge of the public key and digest/signature algorithms to verify the signature:

Listing 5. Bouncy Castle RSA signature verification in CryptoEngine

public boolean RSAVerify (byte [] mesg, byte [] sig)
                                        throws Exception {
  if (RSApubKey == null)
    throw new Exception("Generate RSA keys first!");
  SHA1Digest dig = new SHA1Digest();
  RSAEngine eng = new RSAEngine();
  PSSSigner signer = new PSSSigner(eng, dig, 64);
  signer.init(false, RSApubKey);
  signer.update(mesg, 0, mesg.length);
  return signer.verifySignature(sig);
}

Phaos Micro Foundation

Phaos MF supports DSA and RSA digital signatures. Generating DSA key pairs using the Phaos API is simple. Please note that variable DSApubKeyDer is not the public key itself. Rather, it is a byte array representation of the public key in DER (Distinguished Encoding Rules) format. The public key can be reconstructed from this array using an appropriate algorithm identifier. See more below:

Listing 6. Phaos DSA key pair generation in CryptoEngine

// 1024-bit DSA key
private DSAPrivateKey DSAprivKey;
// This is the DSA public key data you can serialize
private byte [] DSApubKeyDer;
public void generateDSAKeyPair () throws Exception {
  DSAKeyGenParams params =
     new DSAKeyGenParams(1024, RandomBitsSource.getDefault());
  KeyPairGenerator kpg = 
            KeyPairGenerator.getInstance(OIDList.DSA, params);
  KeyPair kp = kpg.generateKeyPair();
  DSAprivKey = (DSAPrivateKey)kp.privateKey;
  ByteArrayOutputStream baos = new ByteArrayOutputStream ();
  ((DSAPublicKey)kp.publicKey).output(baos);
  DSApubKeyDer = baos.toByteArray();
  return;
}

The Phaos API provides convenient ways for serializing keys. Note that in addition to keys themselves, you must serialize DSA key generation parameters for algorithm identification purposes:

Listing 7. Phaos DSA key pair serialization in keygensrc/GenerateAllKeys.java

DSAPublicKey pubKey = (DSAPublicKey)kp.publicKey;
DSAPrivateKey privKey = (DSAPrivateKey)kp.privateKey;
pubKey.output(new FileOutputStream(outdir + "DSApubKey.der"));
privKey.output(new FileOutputStream(outdir + "DSAprivKey.der"));
DSAParams dsaParams =
   new DSAParams(
     new ByteArrayInputStream(
       privKey.createAlgID(true).encodeParameters()));
dsaParams.output(new FileOutputStream(outdir + "DSAparams.der"));

In CryptoEngine's constructor, we reconstruct the private key using private key DER data and the algorithm identifier. The public key DER data is also read in, but the public key itself is not reconstructed until the verification process starts:

Listing 8. Reconstruct Phaos DSA private key and read in public key data in CryptoEngine constructor

// The DSA private key
is = c.getResourceAsStream("/keys/DSAparams.der");
DSAParams params = new DSAParams(is);
AlgorithmIdentifier algID = getDSAalgID(params);
is.close();
is = c.getResourceAsStream("/keys/DSAprivKey.der");
DSAprivKey = new DSAPrivateKey(algID, is);
is.close();
// The DSA public key byte array
is = c.getResourceAsStream("/keys/DSApubKey.der");
baos = new ByteArrayOutputStream();
b = new byte[1];
while ( is.read(b) != -1 ) {
   baos.write(b);
}
is.close();
DSApubKeyDer = baos.toByteArray();
baos.close();

The getDSAalgID() method used in the above listing also retrieves the algorithm identifier from DSA parameters:

Listing 9. Retrieve the algorithm identifier in CryptoEngine

private AlgorithmIdentifier getDSAalgID (DSAParams params) 
                                              throws Exception {
  ByteArrayOutputStream paramsOut = new ByteArrayOutputStream();
  params.output(paramsOut);
  paramsOut.close();
  return new AlgorithmIdentifier(OIDList.DSA, 
                                 paramsOut.toByteArray());
}

Now, we can sign a DSA signature using the private key. Note that both the Phaos algorithm identifier and the signature data itself are written into the output array:

Listing 10. Generate a Phaos DSA signature in CryptoEngine

public byte [] DSASign (byte [] toSign) throws Exception {
  if (DSAprivKey == null)
    throw new Exception("Generate DSA keys first!");
  Signature signature = 
              Signature.getInstance(AlgIDList.SHA1_WITH_DSA,
                                    DSAprivKey);
  byte [] result = 
     signature.sign(toSign, 0, toSign.length).toByteArray(true); 
  DSAParams params = new DSAParams(
      new ByteArrayInputStream(
        DSAprivKey.createAlgID(true).encodeParameters()));
  AlgorithmIdentifier algID = getDSAalgID (params);
  ByteArrayOutputStream baos = new ByteArrayOutputStream ();
  algID.output(baos);
  baos.write(result, 0, result.length);
  baos.flush();
  baos.close();
  return baos.toByteArray();
}

To verify the signature, you must first extract the algorithm identifier from the signature and then construct the public key. Due to the proprietary algorithm identifier format, Phaos signatures are best verified by the Phaos API at the receiving end:

Listing 11. Phaos DSA signature verification in CryptoEngine

public boolean DSAVerify (byte [] mesg, byte [] sig)
                                         throws Exception {
  InputStream is = new ByteArrayInputStream(sig);
  AlgorithmIdentifier algID = new AlgorithmIdentifier(is);
  PooledArray sigBytes = ByteArrayPool.getArray(is.available());
  is.read(sigBytes.buffer, 0, sigBytes.length);
  is.close();
  DSAPublicKey DSApubKey = new DSAPublicKey(algID,
                      new ByteArrayInputStream(DSApubKeyDer));
  Signature signature = 
       Signature.getInstance(AlgIDList.SHA1_WITH_DSA,
                             DSApubKey);
  return signature.verify(mesg, 0, mesg.length,
                        sigBytes.buffer, 0, sigBytes.length);
}

NTRU Neo for Java

As I have mentioned, NTRU Neo for Java probably has the simplest API due to its single algorithm nature. To use any methods in the Neo for Java package, you must first generate a secure random context:

Listing 12. Neo for Java secure context

private RandomNumber rn;
private Context ctx;
public CryptoEngine () {
  try {
    rn = new RandomNumber(NTRUConst.NTRU_SHA1_HASH);
    ctx = new Context(rn);
    ... ...
}

Generating an NTRU key pair for digital signature takes only one line of code. The following code generates an NTRU 251-bit signing key, which has cryptographic strength equivalent to a 1,024-bit RSA key:

Listing 13. NTRU signature key generation in CryptoEngine

public void generateNTRUsgnKeys () throws Exception {
  NTRUsgnKeys = new SgnKeys(ctx, NTRUConst.NTRU_KEYSTRENGTH_251,
                            NTRUConst.NTRU_SHA1_HASH);
  return;
}

Complete key serialization by calling the appropriate export methods:

Listing 14. NTRU signature key serialization in keygensrc/GenerateAllKeys.java

byte [] pubKey = NTRUsgnKeys.exportPubKey(null, 0);
out = new FileOutputStream(outdir + "SgnPubKey.dat");
out.write(pubKey);
out.flush();
out.close();
byte [] privKey = NTRUsgnKeys.exportPrivKey(null, 0);
out = new FileOutputStream(outdir + "SgnPrivKey.dat");
out.write(privKey);
out.flush();
out.close();

Reconstructing serialized keys is also simple:

Listing 15. Reconstruct NTRU signature key pair in CryptoEngine constructor

is = c.getResourceAsStream("/keys/SgnPubKey.dat");
byte [] sgnPubKeyData = readFromStream(is);
is.close();
is = c.getResourceAsStream("/keys/SgnPrivKey.dat");
byte [] sgnPrivKeyData = readFromStream(is);
is.close();
NTRUsgnKeys = new SgnKeys (sgnPubKeyData, 0, sgnPubKeyData.length,
                           sgnPrivKeyData, 0, sgnPrivKeyData.length);

Now, we generate the signature:

Listing 16. Generate NTRU signature in CryptoEngine

public byte [] NTRUSign (byte [] message) throws Exception {
  if ( NTRUsgnKeys == null )
    throw new Exception("Generate NTRU encryption keys first!");
  MessageDigest dig = new MessageDigest(NTRUConst.NTRU_SHA160_HASH);
  Signature sig = new Signature(NTRUConst.NTRU_KEYSTRENGTH_251,
                                NTRUConst.NTRU_SHA160_HASH);
  dig.updateMessageDigest(message, 0, message.length);
  dig.completeMessageDigest();
  sig.sign(ctx, NTRUsgnKeys, dig);
  return sig.export();
}

The receiving party must verify the signature using the NTRU algorithm:

Listing 17. Verify NTRU signature in CryptoEngine

public boolean NTRUVerify (byte [] message, byte [] sigData)
                            throws Exception {
  Signature sig = new Signature(sigData, 0, sigData.length);
  MessageDigest dig = new MessageDigest(sig.getHashAlg());
  dig.updateMessageDigest(message, 0, message.length);
  dig.completeMessageDigest();
  try {
    sig.verify(ctx, NTRUsgnKeys, dig);
    return true;
  } catch (NTRUException e) {
    return false;
  }
}

Secure your mobile data

Advanced mobile commerce applications require content-based and single sign-on security solutions that protect both communication and on-device data. Today's popular HTTPS solution does not meet those requirements due to its point-to-point nature, inflexible protocol design, and slow algorithms.

Third-party vendors have come up with excellent security tools that will meet those future mobile commerce requirements. Those toolkits give developers programmatic access to cryptographic algorithms, especially algorithms specially designed for mobile applications. I encourage you to try those tools and better safeguard your crucial mobile data!

I would like to thank Bouncy Castle lead developer David Hook for help with this article, and Phaos Technology Corporation, NTRU Cryptosystems, and B3 Security for providing evaluation software and technical support.

Michael Yuan is a PhD candidate at the University of Texas, where he is a research associate at the Center for Research in Electronic Commerce and an open source Java developer.
1 2 3 4 Page 3
Page 3 of 4