package org.coinjoin.util; import java.math.BigInteger; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.SecureRandom; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; public class RSABlindSignUtil { private static SecureRandom random; private static KeyPairGenerator kpg; static { // Initialize RSA KeyPair Generator and RNG random = new SecureRandom(); try { kpg = KeyPairGenerator.getInstance("RSA"); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); System.exit(1); } kpg.initialize(2048, new SecureRandom()); } public static KeyPair freshRSAKeyPair() { return kpg.genKeyPair(); } /** * Given m, calculates (m^d)modN * @param p: RSA Private Key * @param blinded: Raw Byte Array representing "m" * @return */ public static byte[] signData(PrivateKey p, byte[] blinded) { BigInteger data = new BigInteger(1, blinded); RSAPrivateKey privKey = (RSAPrivateKey)p; BigInteger sig = data.modPow(privKey.getPrivateExponent(), privKey.getModulus()); return sig.toByteArray(); } public static boolean verifyData(PublicKey p, byte[] data, byte[] signature) { RSAPublicKey pub = (RSAPublicKey)p; BigInteger s = new BigInteger(1, signature); BigInteger e = pub.getPublicExponent(); BigInteger n = pub.getModulus(); BigInteger m = new BigInteger(1, data); return s.modPow(e, n).equals(m); } public static RSABlindedData blindData(PublicKey p, byte[] data) { RSAPublicKey pub = (RSAPublicKey)p; byte[] rand = new byte[pub.getModulus().bitLength() / 8]; BigInteger r = BigInteger.ONE; while(!r.gcd(pub.getModulus()).equals(BigInteger.ONE) || r.equals(BigInteger.ONE) || r.equals(pub.getModulus())) { random.nextBytes(rand); r = new BigInteger(1, rand); } BigInteger bData = ((r.modPow(pub.getPublicExponent(),pub.getModulus())) .multiply(new BigInteger(1, data))).mod(pub.getModulus()); return new RSABlindedData(r, bData.toByteArray()); } public static byte[] unblindSignature(PublicKey p, RSABlindedData bData, byte[] bSig) { RSAPublicKey pub = (RSAPublicKey)p; BigInteger sig = bData.GetMultiplier().modInverse(pub.getModulus()) .multiply(new BigInteger(1, bSig)).mod(pub.getModulus()); return sig.toByteArray(); } public static void main(String[] args) { KeyPair keys1 = RSABlindSignUtil.freshRSAKeyPair(); KeyPair keys2 = RSABlindSignUtil.freshRSAKeyPair(); byte[] data = new byte[256]; for(int i = 0; i < data.length; i++) { data[i] = (byte)i; } byte[] signature = RSABlindSignUtil.signData(keys2.getPrivate(), data); boolean good = RSABlindSignUtil.verifyData(keys2.getPublic(), data, signature); if(good) System.out.println("Yay! It worked!"); else System.out.println("Boo! It did not work!"); } }