blob: 0a1df2a179c676e611691fb4c5f69750e850f580 [file] [log] [blame]
package org.bouncycastle.pqc.jcajce.provider.mceliece;
import java.io.ByteArrayOutputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.digests.SHA224Digest;
import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.digests.SHA384Digest;
import org.bouncycastle.crypto.digests.SHA512Digest;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.crypto.util.DigestFactory;
import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2KeyParameters;
import org.bouncycastle.pqc.crypto.mceliece.McElieceKobaraImaiCipher;
import org.bouncycastle.pqc.jcajce.provider.util.AsymmetricHybridCipher;
public class McElieceKobaraImaiCipherSpi
extends AsymmetricHybridCipher
implements PKCSObjectIdentifiers, X509ObjectIdentifiers
{
// TODO digest needed?
private Digest digest;
private McElieceKobaraImaiCipher cipher;
/**
* buffer to store the input data
*/
private ByteArrayOutputStream buf = new ByteArrayOutputStream();
public McElieceKobaraImaiCipherSpi()
{
buf = new ByteArrayOutputStream();
}
protected McElieceKobaraImaiCipherSpi(Digest digest, McElieceKobaraImaiCipher cipher)
{
this.digest = digest;
this.cipher = cipher;
buf = new ByteArrayOutputStream();
}
/**
* Continue a multiple-part encryption or decryption operation.
*
* @param input byte array containing the next part of the input
* @param inOff index in the array where the input starts
* @param inLen length of the input
* @return the processed byte array.
*/
public byte[] update(byte[] input, int inOff, int inLen)
{
buf.write(input, inOff, inLen);
return new byte[0];
}
/**
* Encrypts or decrypts data in a single-part operation, or finishes a
* multiple-part operation. The data is encrypted or decrypted, depending on
* how this cipher was initialized.
*
* @param input the input buffer
* @param inOff the offset in input where the input starts
* @param inLen the input length
* @return the new buffer with the result
* @throws BadPaddingException if this cipher is in decryption mode, and (un)padding has
* been requested, but the decrypted data is not bounded by
* the appropriate padding bytes
*/
public byte[] doFinal(byte[] input, int inOff, int inLen)
throws BadPaddingException
{
update(input, inOff, inLen);
if (opMode == ENCRYPT_MODE)
{
try
{
return cipher.messageEncrypt(this.pad());
}
catch (Exception e)
{
e.printStackTrace();
}
}
else if (opMode == DECRYPT_MODE)
{
byte[] inputOfDecr = buf.toByteArray();
buf.reset();
try
{
return unpad(cipher.messageDecrypt(inputOfDecr));
}
catch (Exception e)
{
e.printStackTrace();
}
}
return null;
}
protected int encryptOutputSize(int inLen)
{
return 0;
}
protected int decryptOutputSize(int inLen)
{
return 0;
}
protected void initCipherEncrypt(Key key, AlgorithmParameterSpec params,
SecureRandom sr)
throws InvalidKeyException,
InvalidAlgorithmParameterException
{
buf.reset();
CipherParameters param;
param = McElieceCCA2KeysToParams.generatePublicKeyParameter((PublicKey)key);
param = new ParametersWithRandom(param, sr);
digest.reset();
cipher.init(true, param);
}
protected void initCipherDecrypt(Key key, AlgorithmParameterSpec params)
throws InvalidKeyException, InvalidAlgorithmParameterException
{
buf.reset();
CipherParameters param;
param = McElieceCCA2KeysToParams.generatePrivateKeyParameter((PrivateKey)key);
digest.reset();
cipher.init(false, param);
}
public String getName()
{
return "McElieceKobaraImaiCipher";
}
public int getKeySize(Key key)
throws InvalidKeyException
{
McElieceCCA2KeyParameters mcElieceCCA2KeyParameters;
if (key instanceof PublicKey)
{
mcElieceCCA2KeyParameters = (McElieceCCA2KeyParameters)McElieceCCA2KeysToParams.generatePublicKeyParameter((PublicKey)key);
return cipher.getKeySize(mcElieceCCA2KeyParameters);
}
else if (key instanceof PrivateKey)
{
mcElieceCCA2KeyParameters = (McElieceCCA2KeyParameters)McElieceCCA2KeysToParams.generatePrivateKeyParameter((PrivateKey)key);
return cipher.getKeySize(mcElieceCCA2KeyParameters);
}
else
{
throw new InvalidKeyException();
}
}
/**
* Pad and return the message stored in the message buffer.
*
* @return the padded message
*/
private byte[] pad()
{
buf.write(0x01);
byte[] result = buf.toByteArray();
buf.reset();
return result;
}
/**
* Unpad a message.
*
* @param pmBytes the padded message
* @return the message
* @throws BadPaddingException if the padded message is invalid.
*/
private byte[] unpad(byte[] pmBytes)
throws BadPaddingException
{
// find first non-zero byte
int index;
for (index = pmBytes.length - 1; index >= 0 && pmBytes[index] == 0; index--)
{
;
}
// check if padding byte is valid
if (pmBytes[index] != 0x01)
{
throw new BadPaddingException("invalid ciphertext");
}
// extract and return message
byte[] mBytes = new byte[index];
System.arraycopy(pmBytes, 0, mBytes, 0, index);
return mBytes;
}
public byte[] messageEncrypt()
throws IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException
{
byte[] output = null;
try
{
output = cipher.messageEncrypt((this.pad()));
}
catch (Exception e)
{
e.printStackTrace();
}
return output;
}
public byte[] messageDecrypt()
throws IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException
{
byte[] output = null;
byte[] inputOfDecr = buf.toByteArray();
buf.reset();
try
{
output = unpad(cipher.messageDecrypt(inputOfDecr));
}
catch (Exception e)
{
e.printStackTrace();
}
return output;
}
static public class McElieceKobaraImai
extends McElieceKobaraImaiCipherSpi
{
public McElieceKobaraImai()
{
super(DigestFactory.createSHA1(), new McElieceKobaraImaiCipher());
}
}
static public class McElieceKobaraImai224
extends McElieceKobaraImaiCipherSpi
{
public McElieceKobaraImai224()
{
super(DigestFactory.createSHA224(), new McElieceKobaraImaiCipher());
}
}
static public class McElieceKobaraImai256
extends McElieceKobaraImaiCipherSpi
{
public McElieceKobaraImai256()
{
super(DigestFactory.createSHA256(), new McElieceKobaraImaiCipher());
}
}
static public class McElieceKobaraImai384
extends McElieceKobaraImaiCipherSpi
{
public McElieceKobaraImai384()
{
super(DigestFactory.createSHA384(), new McElieceKobaraImaiCipher());
}
}
static public class McElieceKobaraImai512
extends McElieceKobaraImaiCipherSpi
{
public McElieceKobaraImai512()
{
super(DigestFactory.createSHA512(), new McElieceKobaraImaiCipher());
}
}
}