Skip to content

Instantly share code, notes, and snippets.

@icchan
Last active March 4, 2016 09:50
Show Gist options
  • Save icchan/b44663433f560867e326 to your computer and use it in GitHub Desktop.
Save icchan/b44663433f560867e326 to your computer and use it in GitHub Desktop.
Some example functions on how to do digital signatures, both asymmetric and symmetric.
package net.bubblemix.signature;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author ian.chen
*
*/
public class AsymmetricKeySignature {
private static final Logger LOG = LoggerFactory.getLogger(AsymmetricKeySignature.class);
private static final String KEY_ALGORITHM = "RSA";
private static final String SIG_ALGORITHM = "SHA1withRSA";
private static final Charset MESSAGE_ENCODING = StandardCharsets.UTF_8;
private static final Charset SIG_ENCODING = StandardCharsets.UTF_8;
/**
* Generate a public/private key pair for asymmetric key
*
* @return
* @throws NoSuchAlgorithmException
*/
public static KeyPair generateKeyPair() throws NoSuchAlgorithmException {
KeyPairGenerator kpg = KeyPairGenerator.getInstance(KEY_ALGORITHM);
kpg.initialize(1024);
return kpg.genKeyPair();
}
/**
* Generate a public/private key pair for asymmetric key signing
*
* @return Keys as Strings
* @throws NoSuchAlgorithmException
*/
public static StringKeyPair generateStringKeyPair() throws NoSuchAlgorithmException {
KeyPair keyPair = generateKeyPair();
// String used by the signer
PrivateKey privateKey = keyPair.getPrivate();
PKCS8EncodedKeySpec pemcontents = new PKCS8EncodedKeySpec(privateKey.getEncoded());
String privateKeyString = new String(Base64.getEncoder().encode(pemcontents.getEncoded()));
LOG.info("privateKeyString: " + privateKeyString);
// String used by the verifier
PublicKey publicKey = keyPair.getPublic();
String publicKeyString = new String(Base64.getEncoder().encode(publicKey.getEncoded()));
LOG.info("publicKeyString: " + publicKeyString);
StringKeyPair skp = new StringKeyPair();
skp.setPrivateKey(privateKeyString);
skp.setPublicKey(publicKeyString);
return skp;
}
/**
* Sign a string message with a string key
*
* @param message
* @param privateKeyString
* @return
* @throws UnsupportedEncodingException
* @throws NoSuchAlgorithmException
* @throws InvalidKeyException
* @throws SignatureException
* @throws InvalidKeySpecException
*/
public static String sign(String message, String privateKeyString)
throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, InvalidKeySpecException {
KeyFactory kf = KeyFactory.getInstance(KEY_ALGORITHM);
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKeyString.getBytes(SIG_ENCODING)));
PrivateKey privateKey = kf.generatePrivate(spec);
return sign(message.getBytes(MESSAGE_ENCODING), privateKey);
}
/**
* Type safe signing
*
* @param messageBytes
* @param privateKey
* @return
* @throws NoSuchAlgorithmException
* @throws InvalidKeyException
* @throws SignatureException
*/
public static String sign(byte[] messageBytes, PrivateKey privateKey) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
Signature sig = Signature.getInstance(SIG_ALGORITHM);
sig.initSign(privateKey);
sig.update(messageBytes);
byte[] signatureBytes = sig.sign();
return new String(Base64.getEncoder().encode(signatureBytes));
}
/**
*
* @param message raw message
* @param signature base64 encoded signature
* @param publicKeyString base64 encoded public key
* @return
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
* @throws UnsupportedEncodingException
* @throws InvalidKeyException
* @throws SignatureException
* @throws Base64DecodingException
*/
public static boolean verify(String message, String signature, String publicKeyString) throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException {
X509EncodedKeySpec spec = new X509EncodedKeySpec(Base64.getDecoder().decode(publicKeyString.getBytes(SIG_ENCODING)));
KeyFactory kf = KeyFactory.getInstance(KEY_ALGORITHM);
PublicKey publicKey = kf.generatePublic(spec);
return verify(message.getBytes(MESSAGE_ENCODING), Base64.getDecoder().decode(signature), publicKey);
}
/**
*
* @param data raw data
* @param signature raw bytes of the signature
* @param publicKey the public key
* @return
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
* @throws UnsupportedEncodingException
* @throws InvalidKeyException
* @throws SignatureException
*/
public static boolean verify(byte[] data, byte[] signature, PublicKey publicKey) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
Signature sig = Signature.getInstance(SIG_ALGORITHM);
sig.initVerify(publicKey);
sig.update(data);
return sig.verify(signature);
}
}
class StringKeyPair {
private String publicKey;
private String privateKey;
public StringKeyPair() {}
/**
* @return the publicKey
*/
public String getPublicKey() {
return publicKey;
}
/**
* @param publicKey the publicKey to set
*/
public void setPublicKey(String publicKey) {
this.publicKey = publicKey;
}
/**
* @return the privateKey
*/
public String getPrivateKey() {
return privateKey;
}
/**
* @param privateKey the privateKey to set
*/
public void setPrivateKey(String privateKey) {
this.privateKey = privateKey;
}
}
package net.bubblemix.signature;
/**
* @author ian.chen
*
*/
public class DigitalSignaturesExample {
/**
* @param args
*/
public static void main(String[] args) {
String message = "Hello, I am a message";
try {
// Asymmetric style
// generate asymetric key pair
StringKeyPair kp = AsymmetricKeySignature.generateStringKeyPair();
// sign with the private key
String asymSignature = AsymmetricKeySignature.sign(message, kp.getPrivateKey());
// verify with the public key
boolean asymmetricOK = AsymmetricKeySignature.verify(message, asymSignature, kp.getPublicKey());
System.out.println("Asym OK? " + asymmetricOK);
// Symmetric style
// generate a shared key, actually any string is ok for this
// but its generating a hard to guess one is probly better
String sharedSecretKey = SymmetricKeySignature.generateHmacKey();
// generate a signature
String symSignature = SymmetricKeySignature.generateDigest(message, sharedSecretKey);
// verification of a symmetric key signature is just done by
// recreating the signature and checking they match.
System.out.println("symSignature? " + symSignature);
} catch (Exception e) {
// TODO This is just a test, don't do this
e.printStackTrace();
}
}
}
package net.bubblemix.signature;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
public class SymmetricKeySignature {
private static final String DIGEST_ALGORITHM = "HmacSHA256";
private static final Charset MESSAGE_ENCODING = StandardCharsets.UTF_8;
private static final Charset SALT_ENCODING = StandardCharsets.UTF_8;
private static final String SYMMETRIC_KEY_ALGORITHM = "HmacSHA256";
/**
* Generate a key for symmetric key signing
*
* @return
* @throws NoSuchAlgorithmException
*/
public static String generateHmacKey() throws NoSuchAlgorithmException {
KeyGenerator generator = KeyGenerator.getInstance(SYMMETRIC_KEY_ALGORITHM);
generator.init(256);
SecretKey key = generator.generateKey();
return DatatypeConverter.printHexBinary(key.getEncoded());
}
/**
* Generates a HMAC digest
*
* @param data
* @param salt
* @return
* @throws GeneralSecurityException
*/
public static String generateDigest(String data, String salt) throws GeneralSecurityException {
byte[] hmacData = null;
try {
SecretKeySpec secretKey = new SecretKeySpec(salt.getBytes(SALT_ENCODING), DIGEST_ALGORITHM);
Mac mac = Mac.getInstance(DIGEST_ALGORITHM);
mac.init(secretKey);
hmacData = mac.doFinal(data.getBytes(MESSAGE_ENCODING));
return new String(Base64.getEncoder().encode(hmacData));
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
// TODO: handle exception
e.printStackTrace();
throw new GeneralSecurityException(e);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment