package org.bouncycastle.pqc.crypto.newhope;
import java.io.IOException;
import java.security.SecureRandom;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.KeyGenerationParameters;
import org.bouncycastle.crypto.util.DEROtherInfo;
import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers;
import org.bouncycastle.pqc.crypto.ExchangePair;
public class NHOtherInfoGenerator
{
protected final DEROtherInfo.Builder otherInfoBuilder;
protected final SecureRandom random;
protected boolean used = false;
public NHOtherInfoGenerator(AlgorithmIdentifier algorithmID, byte[] partyUInfo, byte[] partyVInfo, SecureRandom random)
{
this.otherInfoBuilder = new DEROtherInfo.Builder(algorithmID, partyUInfo, partyVInfo);
this.random = random;
}
public static class PartyU
extends NHOtherInfoGenerator
{
private AsymmetricCipherKeyPair aKp;
private NHAgreement agreement = new NHAgreement();
public PartyU(AlgorithmIdentifier algorithmID, byte[] partyUInfo, byte[] partyVInfo, java.security.SecureRandom random)
{
super(algorithmID, partyUInfo, partyVInfo, random);
NHKeyPairGenerator kpGen = new NHKeyPairGenerator();
kpGen.init(new KeyGenerationParameters(random, 2048));
aKp = kpGen.generateKeyPair();
agreement.init(aKp.getPrivate());
}
public NHOtherInfoGenerator withSuppPubInfo(byte[] suppPubInfo)
{
this.otherInfoBuilder.withSuppPubInfo(suppPubInfo);
return this;
}
public byte[] getSuppPrivInfoPartA()
{
return getEncoded((NHPublicKeyParameters)aKp.getPublic());
}
public DEROtherInfo generate(byte[] suppPrivInfoPartB)
{
if (used)
{
throw new IllegalStateException("builder already used");
}
used = true;
this.otherInfoBuilder.withSuppPrivInfo(agreement.calculateAgreement(NHOtherInfoGenerator.getPublicKey(suppPrivInfoPartB)));
return otherInfoBuilder.build();
}
}
public static class PartyV
extends NHOtherInfoGenerator
{
public PartyV(AlgorithmIdentifier algorithmID, byte[] partyUInfo, byte[] partyVInfo, SecureRandom random)
{
super(algorithmID, partyUInfo, partyVInfo, random);
}
public NHOtherInfoGenerator withSuppPubInfo(byte[] suppPubInfo)
{
this.otherInfoBuilder.withSuppPubInfo(suppPubInfo);
return this;
}
public byte[] getSuppPrivInfoPartB(byte[] suppPrivInfoPartA)
{
NHExchangePairGenerator exchGen = new NHExchangePairGenerator(random);
ExchangePair bEp = exchGen.generateExchange(getPublicKey(suppPrivInfoPartA));
this.otherInfoBuilder.withSuppPrivInfo(bEp.getSharedValue());
return getEncoded((NHPublicKeyParameters)bEp.getPublicKey());
}
public DEROtherInfo generate()
{
if (used)
{
throw new IllegalStateException("builder already used");
}
used = true;
return otherInfoBuilder.build();
}
}
private static byte[] getEncoded(NHPublicKeyParameters pubKey)
{
SubjectPublicKeyInfo pki;
try
{
AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PQCObjectIdentifiers.newHope);
pki = new SubjectPublicKeyInfo(algorithmIdentifier, pubKey.getPubData());
return pki.getEncoded();
}
catch (IOException e)
{
return null;
}
}
private static NHPublicKeyParameters getPublicKey(byte[] enc)
{
SubjectPublicKeyInfo pki = SubjectPublicKeyInfo.getInstance(enc);
return new NHPublicKeyParameters(pki.getPublicKeyData().getOctets());
}
}