Do You Remember Carbon Copies? Here’s Blind Signatures

Do you remember the days of carbon copies? Well, they were often used as a receipt, and where there was blue carbon paper which copied your…

Do You Remember Carbon Copies? Here’s Blind Signatures

Do you remember the days of carbon copies? Well, they were often used as a receipt, and where there was blue carbon paper which copied your writing onto another sheet:

Now, let’s see if we can use a carbon copy to allow Bob to cast a trusted vote in an election. First, Bob makes his vote on a piece of paper and then puts it into a special envelope. He gives this envelope to Peggy, and who seals it. But, there is a special place for Peggy to sign on the envelope, which has a carbon copy strip. When she signs the outside of the envelope, her signature is copied to the vote inside the envelope. So, when Victor opens up the envelope, he examines Bob’s vote and can see if it has been signed by Peggy, and so he trusts the vote. Overall, Peggy never gets to see Bob’s vote but can sign for it.

In a digital form, Peggy (the “prover”) creates a key pair: a public key and a private key. She will sign with her private key and then prove her signature with her public key.

With a blinded signature, Bob creates a blinded version of his message for Peggy to sign with her private key. She thus cannot see what the message is that she is signing. Then, Bob will unblind the message and send the signature to Victor (the “verifier”), and who will verify it with Peggy’s public key.

We can create an RSA key pair for Peggy with the Bouncy Castle library with [here]:

RsaKeyPairGenerator pGen = new RsaKeyPairGenerator();
pGen.Init(new KeyGenerationParameters(new SecureRandom(), s));
var pair = pGen.GenerateKeyPair();

Next we can generate the blinding factor [here]:

// "Blind" the signature 
PssSigner signer = new PssSigner(new RsaBlindingEngine(), new Sha256Digest(), 20);

signer.Init(true, blindingParams);
signer.BlockUpdate(data, 0, data.Length);
byte[] sig = signer.GenerateSignature(); // get signature ready to sign

Next we can get the signer to sign the blinded message [here]:

// Sign the blinded message
RsaEngine engine = new RsaEngine();
engine.Init(true, pair.Private);
var blindsign = engine.ProcessBlock(sig, 0, sig.Length);

Finally, we can then unblind the signature [here]:

// Unblind signature
RsaBlindingEngine blindingEngine = new RsaBlindingEngine();
blindingEngine.Init(false, blindingParams);
byte[] signew = blindingEngine.ProcessBlock(blindsign, 0, blindsign.Length);

Finally, we can test the signature with the public key [here]:

// Verify signature
signer = new PssSigner(new RsaEngine(), new Sha256Digest(), 20);
signer.Init(false,pair.Public);
signer.BlockUpdate(data, 0,data.Length);
var rtn=signer.VerifySignature(signew);

In this blindsign is the blinded signature, and signnew is the unblinded version. The full code is [here]:

namespace Blinded
{
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Crypto.Generators;
using System.Text;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Signers;

class Program
{
public static byte[] getRandomBytes(int count) {
byte[] bytes = new byte[count];
new SecureRandom().NextBytes(bytes);
return bytes;
}
static void Main(string[] args)
{
string size="512";
string str="Hello";

if (args.Length >0) str=args[0];
if (args.Length >1) size=args[1];
int s = Convert.ToInt32(size);

try {
byte[] data = Encoding.ASCII.GetBytes(str);

RsaKeyPairGenerator pGen = new RsaKeyPairGenerator();
pGen.Init(new KeyGenerationParameters(new SecureRandom(), s));
var pair = pGen.GenerateKeyPair();

// Generate a blinding factor for public key
var blindingFactorGenerator = new RsaBlindingFactorGenerator();
blindingFactorGenerator.Init((RsaKeyParameters)pair.Public);
var blindingFactor = blindingFactorGenerator.GenerateBlindingFactor();

var blindingParams = new RsaBlindingParameters((RsaKeyParameters)pair.Public, blindingFactor);

// "Blind" the signature
PssSigner signer = new PssSigner(new RsaBlindingEngine(), new Sha256Digest(), 20);

signer.Init(true, blindingParams);
signer.BlockUpdate(data, 0, data.Length);
byte[] sig = signer.GenerateSignature(); // get signature ready to sign

// Sign the blinded message
RsaEngine engine = new RsaEngine();
engine.Init(true, pair.Private);
var blindsign = engine.ProcessBlock(sig, 0, sig.Length);
// Unblind signature
RsaBlindingEngine blindingEngine = new RsaBlindingEngine();
blindingEngine.Init(false, blindingParams);
byte[] signew = blindingEngine.ProcessBlock(blindsign, 0, blindsign.Length);
// Verify signature
signer = new PssSigner(new RsaEngine(), new Sha256Digest(), 20);
signer.Init(false,pair.Public);
signer.BlockUpdate(data, 0,data.Length);
var rtn=signer.VerifySignature(signew);

RsaPrivateCrtKeyParameters priv = ((RsaPrivateCrtKeyParameters)pair.Private);

Console.WriteLine("Message:\t{0}",str);
Console.WriteLine("Key size:\t{0}",size);
Console.WriteLine("RSA N:\t{0}",priv.Modulus);
Console.WriteLine("RSA d:\t{0}",priv.Exponent);
Console.WriteLine(" p:\t{0}",priv.P);
Console.WriteLine(" q:\t{0}",priv.Q);
Console.WriteLine("RSA e:\t{0}",priv.PublicExponent);
Console.WriteLine("\nVerified: {0}",rtn);
Console.WriteLine("\nBlinded signature: {0}",Convert.ToHexString(sig));
Console.WriteLine("\nUnblinded signature: {0}",Convert.ToHexString(signew));


} catch (Exception e) {
Console.WriteLine("Error: {0}",e.Message);
}
}
}
}

A sample run with 512-bit RSA keys is [here]:

Message:	Hello
Key size: 512
RSA N: 9501414863243560066341462321471935054349724589264480077004243951542388503653727344471281608010109011697337788541834467710255966249029373477947190794335749
RSA d: 2101381780296378860515225378314157844351619437250621884983108991190184936237638580115285913901635086465261269564456312666972810119721146925213265877744977
p: 103843561217129126640162913737503047288949391266673123278871357435590829952973
q: 91497390419583276758809687817207537680958433833057531824198623481567481042713
RSA e: 65537
Verified: True
Blinded signature: 620E2C25B31A7C00C1215A794745FB932C033BB3F862C88DF8824A708E4578C50DC2AB1E8EA3861A061D0AE58A817AFC6354C03779E9452666D907F597833688
Unblinded signature: 89BF01FAFB54F1D3FD6E8A268C440C734ADA5278EC8B57AEE1820549F04EF211DDFBBCC50955CA7BD9219327B4F9C8FCEBBD27955BA26B9D94B33BDC08C2C79F

and for 1,024-bit keys [here]:

Message:	Hello
Key size: 1024
RSA N: 139548682571491209896930381437672113042327208449829748322514290538687189078048164988981349592530370189327510154933510422562083105153152344607444107456757376117862645349423738671566497248108552420745388212422766902684923943063663057955365608366820150436711243094876173507265370018871914636913598338441132778809
RSA d: 27824776988616527844242759959057941882915159320966022799402711317489278472883934205006542652248205020813238917704405869155286646880217560510212183563348592431663079267637773281805655476216223401473610184553107897844201311608739306238248205511135675309880115197142940933925989320969649061165998344980227977023
p: 13032765743864262240243994099275033179906162342609640366925766837328628482061206314284306553582177344756639850907062764127697420891236779960986996883068299
q: 10707526346599898307490537981065114199140764335775726189355068810061238169486289049591166958838947438947930046738035340533530298324680283931322366828556491
RSA e: 65537
Verified: True
Blinded signature: 01B299653C0B4C0A952464BD26DD8833401DD02B688B9DB5240D844BCBB1048127BA9702D4CA51858A7286181CFABDA67C6BAAB40423372BD2BFB7041013BDEE50CFB7E7916A73B95574599857DB406EA6F6BFB2A39A75B83497CB08C128DD4BB63D31D0763A73C7A4702984B2A4148B2D974A93F57593481C328E5A5AEC604C
Unblinded signature: 24A4C3F4430E6D6DC715E32976324BA918A97D5444331855892AC47499F745D60C3A5B6E1A840CDFD860E17371843DF5706CAD76D3668D1481605F0D4180290AD801D338B77728890F53F4BEA83BB2128CD43EC4181BA13E16A170F1D5DD94ED8F4A706AF5A6B3A407300AA82A308EAF927294F7955885677A4E559022B40525

Conclusions

And there you go, a carbon copy of a signature that is fit for the 21st Century.