forked from I2P_Developers/i2p.i2p
BouncyCastle 1.80 source files, unmodified, as a base for future merges
will not compile
This commit is contained in:
@ -0,0 +1,61 @@
|
||||
package org.bouncycastle.crypto;
|
||||
|
||||
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
|
||||
|
||||
/**
|
||||
* a holding class for public/private parameter pairs.
|
||||
*/
|
||||
public class AsymmetricCipherKeyPair
|
||||
{
|
||||
private AsymmetricKeyParameter publicParam;
|
||||
private AsymmetricKeyParameter privateParam;
|
||||
|
||||
/**
|
||||
* basic constructor.
|
||||
*
|
||||
* @param publicParam a public key parameters object.
|
||||
* @param privateParam the corresponding private key parameters.
|
||||
*/
|
||||
public AsymmetricCipherKeyPair(
|
||||
AsymmetricKeyParameter publicParam,
|
||||
AsymmetricKeyParameter privateParam)
|
||||
{
|
||||
this.publicParam = publicParam;
|
||||
this.privateParam = privateParam;
|
||||
}
|
||||
|
||||
/**
|
||||
* basic constructor.
|
||||
*
|
||||
* @param publicParam a public key parameters object.
|
||||
* @param privateParam the corresponding private key parameters.
|
||||
* @deprecated use AsymmetricKeyParameter
|
||||
*/
|
||||
public AsymmetricCipherKeyPair(
|
||||
CipherParameters publicParam,
|
||||
CipherParameters privateParam)
|
||||
{
|
||||
this.publicParam = (AsymmetricKeyParameter)publicParam;
|
||||
this.privateParam = (AsymmetricKeyParameter)privateParam;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the public key parameters.
|
||||
*
|
||||
* @return the public key parameters.
|
||||
*/
|
||||
public AsymmetricKeyParameter getPublic()
|
||||
{
|
||||
return publicParam;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the private key parameters.
|
||||
*
|
||||
* @return the private key parameters.
|
||||
*/
|
||||
public AsymmetricKeyParameter getPrivate()
|
||||
{
|
||||
return privateParam;
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package org.bouncycastle.crypto;
|
||||
|
||||
/**
|
||||
* interface that a public/private key pair generator should conform to.
|
||||
*/
|
||||
public interface AsymmetricCipherKeyPairGenerator
|
||||
{
|
||||
/**
|
||||
* intialise the key pair generator.
|
||||
*
|
||||
* @param param the parameters the key pair is to be initialised with.
|
||||
*/
|
||||
public void init(KeyGenerationParameters param);
|
||||
|
||||
/**
|
||||
* return an AsymmetricCipherKeyPair containing the generated keys.
|
||||
*
|
||||
* @return an AsymmetricCipherKeyPair containing the generated keys.
|
||||
*/
|
||||
public AsymmetricCipherKeyPair generateKeyPair();
|
||||
}
|
||||
|
@ -0,0 +1,8 @@
|
||||
package org.bouncycastle.crypto;
|
||||
|
||||
/**
|
||||
* all parameter classes implement this.
|
||||
*/
|
||||
public interface CipherParameters
|
||||
{
|
||||
}
|
48
router/java/src/org/bouncycastle/crypto/CryptoException.java
Normal file
48
router/java/src/org/bouncycastle/crypto/CryptoException.java
Normal file
@ -0,0 +1,48 @@
|
||||
package org.bouncycastle.crypto;
|
||||
|
||||
/**
|
||||
* the foundation class for the hard exceptions thrown by the crypto packages.
|
||||
*/
|
||||
public class CryptoException
|
||||
extends Exception
|
||||
{
|
||||
private Throwable cause;
|
||||
|
||||
/**
|
||||
* base constructor.
|
||||
*/
|
||||
public CryptoException()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* create a CryptoException with the given message.
|
||||
*
|
||||
* @param message the message to be carried with the exception.
|
||||
*/
|
||||
public CryptoException(
|
||||
String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a CryptoException with the given message and underlying cause.
|
||||
*
|
||||
* @param message message describing exception.
|
||||
* @param cause the throwable that was the underlying cause.
|
||||
*/
|
||||
public CryptoException(
|
||||
String message,
|
||||
Throwable cause)
|
||||
{
|
||||
super(message);
|
||||
|
||||
this.cause = cause;
|
||||
}
|
||||
|
||||
public Throwable getCause()
|
||||
{
|
||||
return cause;
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package org.bouncycastle.crypto;
|
||||
|
||||
public interface CryptoServiceProperties
|
||||
{
|
||||
int bitsOfSecurity();
|
||||
|
||||
String getServiceName();
|
||||
|
||||
CryptoServicePurpose getPurpose();
|
||||
|
||||
Object getParams();
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package org.bouncycastle.crypto;
|
||||
|
||||
public enum CryptoServicePurpose
|
||||
{
|
||||
AGREEMENT,
|
||||
ENCRYPTION,
|
||||
DECRYPTION,
|
||||
KEYGEN,
|
||||
SIGNING, // for signatures (and digests)
|
||||
VERIFYING,
|
||||
AUTHENTICATION, // for MACs (and digests)
|
||||
VERIFICATION,
|
||||
PRF,
|
||||
ANY
|
||||
}
|
@ -0,0 +1,541 @@
|
||||
package org.bouncycastle.crypto;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.AccessController;
|
||||
import java.security.Permission;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.bouncycastle.asn1.x9.X9ECParameters;
|
||||
import org.bouncycastle.crypto.params.DHParameters;
|
||||
import org.bouncycastle.crypto.params.DHValidationParameters;
|
||||
import org.bouncycastle.crypto.params.DSAParameters;
|
||||
import org.bouncycastle.crypto.params.DSAValidationParameters;
|
||||
import org.bouncycastle.util.Properties;
|
||||
import org.bouncycastle.util.Strings;
|
||||
import org.bouncycastle.util.encoders.Hex;
|
||||
|
||||
/**
|
||||
* Basic registrar class for providing defaults for cryptography services in this module.
|
||||
*/
|
||||
public final class CryptoServicesRegistrar
|
||||
{
|
||||
private static final Logger LOG = Logger.getLogger(CryptoServicesRegistrar.class.getName());
|
||||
|
||||
private static final Permission CanSetDefaultProperty = new CryptoServicesPermission(CryptoServicesPermission.GLOBAL_CONFIG);
|
||||
private static final Permission CanSetThreadProperty = new CryptoServicesPermission(CryptoServicesPermission.THREAD_LOCAL_CONFIG);
|
||||
private static final Permission CanSetDefaultRandom = new CryptoServicesPermission(CryptoServicesPermission.DEFAULT_RANDOM);
|
||||
private static final Permission CanSetConstraints = new CryptoServicesPermission(CryptoServicesPermission.CONSTRAINTS);
|
||||
|
||||
private static final ThreadLocal<Map<String, Object[]>> threadProperties = new ThreadLocal<Map<String, Object[]>>();
|
||||
private static final Map<String, Object[]> globalProperties = Collections.synchronizedMap(new HashMap<String, Object[]>());
|
||||
private static final SecureRandomProvider defaultRandomProviderImpl = new ThreadLocalSecureRandomProvider();
|
||||
|
||||
private static final CryptoServicesConstraints noConstraintsImpl = new CryptoServicesConstraints()
|
||||
{
|
||||
public void check(CryptoServiceProperties service)
|
||||
{
|
||||
// anything goes.
|
||||
}
|
||||
};
|
||||
|
||||
private static final AtomicReference<SecureRandomProvider> defaultSecureRandomProvider = new AtomicReference<SecureRandomProvider>();
|
||||
private static final boolean preconfiguredConstraints;
|
||||
private static final AtomicReference<CryptoServicesConstraints> servicesConstraints = new AtomicReference<CryptoServicesConstraints>();
|
||||
|
||||
static
|
||||
{
|
||||
// default domain parameters for DSA and Diffie-Hellman
|
||||
|
||||
DSAParameters def512Params = new DSAParameters(
|
||||
new BigInteger("fca682ce8e12caba26efccf7110e526db078b05edecbcd1eb4a208f3ae1617ae01f35b91a47e6df63413c5e12ed0899bcd132acd50d99151bdc43ee737592e17", 16),
|
||||
new BigInteger("962eddcc369cba8ebb260ee6b6a126d9346e38c5", 16),
|
||||
new BigInteger("678471b27a9cf44ee91a49c5147db1a9aaf244f05a434d6486931d2d14271b9e35030b71fd73da179069b32e2935630e1c2062354d0da20a6c416e50be794ca4", 16),
|
||||
new DSAValidationParameters(Hex.decodeStrict("b869c82b35d70e1b1ff91b28e37a62ecdc34409b"), 123));
|
||||
|
||||
DSAParameters def768Params = new DSAParameters(
|
||||
new BigInteger("e9e642599d355f37c97ffd3567120b8e25c9cd43e927b3a9670fbec5" +
|
||||
"d890141922d2c3b3ad2480093799869d1e846aab49fab0ad26d2ce6a" +
|
||||
"22219d470bce7d777d4a21fbe9c270b57f607002f3cef8393694cf45" +
|
||||
"ee3688c11a8c56ab127a3daf", 16),
|
||||
new BigInteger("9cdbd84c9f1ac2f38d0f80f42ab952e7338bf511", 16),
|
||||
new BigInteger("30470ad5a005fb14ce2d9dcd87e38bc7d1b1c5facbaecbe95f190aa7" +
|
||||
"a31d23c4dbbcbe06174544401a5b2c020965d8c2bd2171d366844577" +
|
||||
"1f74ba084d2029d83c1c158547f3a9f1a2715be23d51ae4d3e5a1f6a" +
|
||||
"7064f316933a346d3f529252", 16),
|
||||
new DSAValidationParameters(Hex.decodeStrict("77d0f8c4dad15eb8c4f2f8d6726cefd96d5bb399"), 263));
|
||||
|
||||
DSAParameters def1024Params = new DSAParameters(
|
||||
new BigInteger("fd7f53811d75122952df4a9c2eece4e7f611b7523cef4400c31e3f80" +
|
||||
"b6512669455d402251fb593d8d58fabfc5f5ba30f6cb9b556cd7813b" +
|
||||
"801d346ff26660b76b9950a5a49f9fe8047b1022c24fbba9d7feb7c6" +
|
||||
"1bf83b57e7c6a8a6150f04fb83f6d3c51ec3023554135a169132f675" +
|
||||
"f3ae2b61d72aeff22203199dd14801c7", 16),
|
||||
new BigInteger("9760508f15230bccb292b982a2eb840bf0581cf5", 16),
|
||||
new BigInteger("f7e1a085d69b3ddecbbcab5c36b857b97994afbbfa3aea82f9574c0b" +
|
||||
"3d0782675159578ebad4594fe67107108180b449167123e84c281613" +
|
||||
"b7cf09328cc8a6e13c167a8b547c8d28e0a3ae1e2bb3a675916ea37f" +
|
||||
"0bfa213562f1fb627a01243bcca4f1bea8519089a883dfe15ae59f06" +
|
||||
"928b665e807b552564014c3bfecf492a", 16),
|
||||
new DSAValidationParameters(Hex.decodeStrict("8d5155894229d5e689ee01e6018a237e2cae64cd"), 92));
|
||||
|
||||
DSAParameters def2048Params = new DSAParameters(
|
||||
new BigInteger("95475cf5d93e596c3fcd1d902add02f427f5f3c7210313bb45fb4d5b" +
|
||||
"b2e5fe1cbd678cd4bbdd84c9836be1f31c0777725aeb6c2fc38b85f4" +
|
||||
"8076fa76bcd8146cc89a6fb2f706dd719898c2083dc8d896f84062e2" +
|
||||
"c9c94d137b054a8d8096adb8d51952398eeca852a0af12df83e475aa" +
|
||||
"65d4ec0c38a9560d5661186ff98b9fc9eb60eee8b030376b236bc73b" +
|
||||
"e3acdbd74fd61c1d2475fa3077b8f080467881ff7e1ca56fee066d79" +
|
||||
"506ade51edbb5443a563927dbc4ba520086746175c8885925ebc64c6" +
|
||||
"147906773496990cb714ec667304e261faee33b3cbdf008e0c3fa906" +
|
||||
"50d97d3909c9275bf4ac86ffcb3d03e6dfc8ada5934242dd6d3bcca2" +
|
||||
"a406cb0b", 16),
|
||||
new BigInteger("f8183668ba5fc5bb06b5981e6d8b795d30b8978d43ca0ec572e37e09939a9773", 16),
|
||||
new BigInteger("42debb9da5b3d88cc956e08787ec3f3a09bba5f48b889a74aaf53174" +
|
||||
"aa0fbe7e3c5b8fcd7a53bef563b0e98560328960a9517f4014d3325f" +
|
||||
"c7962bf1e049370d76d1314a76137e792f3f0db859d095e4a5b93202" +
|
||||
"4f079ecf2ef09c797452b0770e1350782ed57ddf794979dcef23cb96" +
|
||||
"f183061965c4ebc93c9c71c56b925955a75f94cccf1449ac43d586d0" +
|
||||
"beee43251b0b2287349d68de0d144403f13e802f4146d882e057af19" +
|
||||
"b6f6275c6676c8fa0e3ca2713a3257fd1b27d0639f695e347d8d1cf9" +
|
||||
"ac819a26ca9b04cb0eb9b7b035988d15bbac65212a55239cfc7e58fa" +
|
||||
"e38d7250ab9991ffbc97134025fe8ce04c4399ad96569be91a546f49" +
|
||||
"78693c7a", 16),
|
||||
new DSAValidationParameters(Hex.decodeStrict("b0b4417601b59cbc9d8ac8f935cadaec4f5fbb2f23785609ae466748d9b5a536"), 497));
|
||||
|
||||
localSetGlobalProperty(Property.DSA_DEFAULT_PARAMS, def512Params, def768Params, def1024Params, def2048Params);
|
||||
localSetGlobalProperty(Property.DH_DEFAULT_PARAMS, toDH(def512Params), toDH(def768Params), toDH(def1024Params), toDH(def2048Params));
|
||||
|
||||
servicesConstraints.set(getDefaultConstraints());
|
||||
preconfiguredConstraints = (servicesConstraints.get() != noConstraintsImpl);
|
||||
}
|
||||
|
||||
private CryptoServicesRegistrar()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default source of randomness.
|
||||
*
|
||||
* @return the default SecureRandom
|
||||
*/
|
||||
public static SecureRandom getSecureRandom()
|
||||
{
|
||||
defaultSecureRandomProvider.compareAndSet(null, defaultRandomProviderImpl);
|
||||
|
||||
return defaultSecureRandomProvider.get().get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return either the passed-in SecureRandom, or if it is null, then the default source of randomness.
|
||||
*
|
||||
* @param secureRandom the SecureRandom to use if it is not null.
|
||||
* @return the SecureRandom parameter if it is not null, or else the default SecureRandom
|
||||
*/
|
||||
public static SecureRandom getSecureRandom(SecureRandom secureRandom)
|
||||
{
|
||||
return null == secureRandom ? getSecureRandom() : secureRandom;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a default secure random to be used where none is otherwise provided.
|
||||
*
|
||||
* @param secureRandom the SecureRandom to use as the default.
|
||||
*/
|
||||
public static void setSecureRandom(final SecureRandom secureRandom)
|
||||
{
|
||||
checkPermission(CanSetDefaultRandom);
|
||||
|
||||
if (secureRandom == null)
|
||||
{
|
||||
defaultSecureRandomProvider.set(defaultRandomProviderImpl);
|
||||
}
|
||||
else
|
||||
{
|
||||
defaultSecureRandomProvider.set(new SecureRandomProvider()
|
||||
{
|
||||
public SecureRandom get()
|
||||
{
|
||||
return secureRandom;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a default secure random provider to be used where none is otherwise provided.
|
||||
*
|
||||
* @param secureRandomProvider a provider SecureRandom to use when a default SecureRandom is requested.
|
||||
*/
|
||||
public static void setSecureRandomProvider(SecureRandomProvider secureRandomProvider)
|
||||
{
|
||||
checkPermission(CanSetDefaultRandom);
|
||||
|
||||
defaultSecureRandomProvider.set(secureRandomProvider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current algorithm/services constraints.
|
||||
*
|
||||
* @return the algorithm/services constraints.
|
||||
*/
|
||||
public static CryptoServicesConstraints getServicesConstraints()
|
||||
{
|
||||
return servicesConstraints.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check a service to make sure it meets the current constraints.
|
||||
*
|
||||
* @param cryptoService the service to be checked.
|
||||
* @throws CryptoServiceConstraintsException if the service violates the current constraints.
|
||||
*/
|
||||
public static void checkConstraints(CryptoServiceProperties cryptoService)
|
||||
{
|
||||
servicesConstraints.get().check(cryptoService);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current algorithm constraints.
|
||||
*/
|
||||
public static void setServicesConstraints(CryptoServicesConstraints constraints)
|
||||
{
|
||||
checkPermission(CanSetConstraints);
|
||||
|
||||
CryptoServicesConstraints newConstraints = (constraints == null) ? noConstraintsImpl : constraints;
|
||||
|
||||
if (preconfiguredConstraints)
|
||||
{
|
||||
if (Properties.isOverrideSet("org.bouncycastle.constraints.allow_override"))
|
||||
{
|
||||
servicesConstraints.set(newConstraints);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG.warning("attempt to override pre-configured constraints ignored");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: should this only be allowed once?
|
||||
servicesConstraints.set(newConstraints);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default value for a particular property if one exists. The look up is done on the thread's local
|
||||
* configuration first and then on the global configuration in no local configuration exists.
|
||||
*
|
||||
* @param property the property to look up.
|
||||
* @param <T> the type to be returned
|
||||
* @return null if the property is not set, the default value otherwise,
|
||||
*/
|
||||
public static <T> T getProperty(Property property)
|
||||
{
|
||||
Object[] values = lookupProperty(property);
|
||||
|
||||
if (values != null)
|
||||
{
|
||||
return (T)values[0];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Object[] lookupProperty(Property property)
|
||||
{
|
||||
Map<String, Object[]> properties = threadProperties.get();
|
||||
Object[] values;
|
||||
|
||||
if (properties == null || !properties.containsKey(property.name))
|
||||
{
|
||||
values = globalProperties.get(property.name);
|
||||
}
|
||||
else
|
||||
{
|
||||
values = properties.get(property.name);
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array representing the current values for a sized property such as DH_DEFAULT_PARAMS or
|
||||
* DSA_DEFAULT_PARAMS.
|
||||
*
|
||||
* @param property the name of the property to look up.
|
||||
* @param <T> the base type of the array to be returned.
|
||||
* @return null if the property is not set, an array of the current values otherwise.
|
||||
*/
|
||||
public static <T> T[] getSizedProperty(Property property)
|
||||
{
|
||||
Object[] values = lookupProperty(property);
|
||||
|
||||
if (values == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return (T[])values.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the value for a specific size for a sized property such as DH_DEFAULT_PARAMS or
|
||||
* DSA_DEFAULT_PARAMS.
|
||||
*
|
||||
* @param property the name of the property to look up.
|
||||
* @param size the size (in bits) of the defining value in the property type.
|
||||
* @param <T> the type of the value to be returned.
|
||||
* @return the current value for the size, null if there is no value set,
|
||||
*/
|
||||
public static <T> T getSizedProperty(Property property, int size)
|
||||
{
|
||||
Object[] values = lookupProperty(property);
|
||||
|
||||
if (values == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (property.type.isAssignableFrom(DHParameters.class))
|
||||
{
|
||||
for (int i = 0; i != values.length; i++)
|
||||
{
|
||||
DHParameters params = (DHParameters)values[i];
|
||||
|
||||
if (params.getP().bitLength() == size)
|
||||
{
|
||||
return (T)params;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (property.type.isAssignableFrom(DSAParameters.class))
|
||||
{
|
||||
for (int i = 0; i != values.length; i++)
|
||||
{
|
||||
DSAParameters params = (DSAParameters)values[i];
|
||||
|
||||
if (params.getP().bitLength() == size)
|
||||
{
|
||||
return (T)params;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of the the passed in property on the current thread only. More than
|
||||
* one value can be passed in for a sized property. If more than one value is provided the
|
||||
* first value in the argument list becomes the default value.
|
||||
*
|
||||
* @param property the name of the property to set.
|
||||
* @param propertyValue the values to assign to the property.
|
||||
* @param <T> the base type of the property value.
|
||||
*/
|
||||
public static <T> void setThreadProperty(Property property, T... propertyValue)
|
||||
{
|
||||
checkPermission(CanSetThreadProperty);
|
||||
|
||||
if (!property.type.isAssignableFrom(propertyValue[0].getClass()))
|
||||
{
|
||||
throw new IllegalArgumentException("Bad property value passed");
|
||||
}
|
||||
|
||||
localSetThread(property, propertyValue.clone());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of the the passed in property globally in the JVM. More than
|
||||
* one value can be passed in for a sized property. If more than one value is provided the
|
||||
* first value in the argument list becomes the default value.
|
||||
*
|
||||
* @param property the name of the property to set.
|
||||
* @param propertyValue the values to assign to the property.
|
||||
* @param <T> the base type of the property value.
|
||||
*/
|
||||
public static <T> void setGlobalProperty(Property property, T... propertyValue)
|
||||
{
|
||||
checkPermission(CanSetDefaultProperty);
|
||||
|
||||
localSetGlobalProperty(property, propertyValue.clone());
|
||||
}
|
||||
|
||||
private static <T> void localSetThread(Property property, T[] propertyValue)
|
||||
{
|
||||
Map<String, Object[]> properties = threadProperties.get();
|
||||
|
||||
if (properties == null)
|
||||
{
|
||||
properties = new HashMap<String, Object[]>();
|
||||
threadProperties.set(properties);
|
||||
}
|
||||
|
||||
properties.put(property.name, propertyValue);
|
||||
}
|
||||
|
||||
private static <T> void localSetGlobalProperty(Property property, T... propertyValue)
|
||||
{
|
||||
if (!property.type.isAssignableFrom(propertyValue[0].getClass()))
|
||||
{
|
||||
throw new IllegalArgumentException("Bad property value passed");
|
||||
}
|
||||
|
||||
// set the property for the current thread as well to avoid mass confusion
|
||||
localSetThread(property, propertyValue);
|
||||
|
||||
globalProperties.put(property.name, propertyValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the global value for the passed in property.
|
||||
*
|
||||
* @param property the property to be cleared.
|
||||
* @param <T> the base type of the property value
|
||||
* @return an array of T if a value was previously set, null otherwise.
|
||||
*/
|
||||
public static <T> T[] clearGlobalProperty(Property property)
|
||||
{
|
||||
checkPermission(CanSetDefaultProperty);
|
||||
|
||||
// clear the property for the current thread as well to avoid confusion
|
||||
localClearThreadProperty(property);
|
||||
|
||||
return (T[])globalProperties.remove(property.name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the thread local value for the passed in property.
|
||||
*
|
||||
* @param property the property to be cleared.
|
||||
* @param <T> the base type of the property value
|
||||
* @return an array of T if a value was previously set, null otherwise.
|
||||
*/
|
||||
public static <T> T[] clearThreadProperty(Property property)
|
||||
{
|
||||
checkPermission(CanSetThreadProperty);
|
||||
|
||||
return (T[])localClearThreadProperty(property);
|
||||
}
|
||||
|
||||
private static Object[] localClearThreadProperty(Property property)
|
||||
{
|
||||
Map<String, Object[]> properties = threadProperties.get();
|
||||
|
||||
if (properties == null)
|
||||
{
|
||||
properties = new HashMap<String, Object[]>();
|
||||
threadProperties.set(properties);
|
||||
}
|
||||
|
||||
return properties.remove(property.name);
|
||||
}
|
||||
|
||||
private static void checkPermission(final Permission permission)
|
||||
{
|
||||
final SecurityManager securityManager = System.getSecurityManager();
|
||||
|
||||
if (securityManager != null)
|
||||
{
|
||||
AccessController.doPrivileged(new PrivilegedAction<Object>()
|
||||
{
|
||||
public Object run()
|
||||
{
|
||||
securityManager.checkPermission(permission);
|
||||
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static DHParameters toDH(DSAParameters dsaParams)
|
||||
{
|
||||
int pSize = dsaParams.getP().bitLength();
|
||||
int m = chooseLowerBound(pSize);
|
||||
return new DHParameters(dsaParams.getP(), dsaParams.getG(), dsaParams.getQ(), m, 0, null,
|
||||
new DHValidationParameters(dsaParams.getValidationParameters().getSeed(), dsaParams.getValidationParameters().getCounter()));
|
||||
}
|
||||
|
||||
// based on lower limit of at least 2^{2 * bits_of_security}
|
||||
private static int chooseLowerBound(int pSize)
|
||||
{
|
||||
int m = 160;
|
||||
if (pSize > 1024)
|
||||
{
|
||||
if (pSize <= 2048)
|
||||
{
|
||||
m = 224;
|
||||
}
|
||||
else if (pSize <= 3072)
|
||||
{
|
||||
m = 256;
|
||||
}
|
||||
else if (pSize <= 7680)
|
||||
{
|
||||
m = 384;
|
||||
}
|
||||
else
|
||||
{
|
||||
m = 512;
|
||||
}
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
private static CryptoServicesConstraints getDefaultConstraints()
|
||||
{
|
||||
// TODO: return one based on system/security properties if set.
|
||||
|
||||
return noConstraintsImpl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Available properties that can be set.
|
||||
*/
|
||||
public static final class Property
|
||||
{
|
||||
/**
|
||||
* The parameters to be used for processing implicitlyCA X9.62 parameters
|
||||
*/
|
||||
public static final Property EC_IMPLICITLY_CA = new Property("ecImplicitlyCA", X9ECParameters.class);
|
||||
/**
|
||||
* The default parameters for a particular size of Diffie-Hellman key.This is a sized property.
|
||||
*/
|
||||
public static final Property DH_DEFAULT_PARAMS = new Property("dhDefaultParams", DHParameters.class);
|
||||
/**
|
||||
* The default parameters for a particular size of DSA key. This is a sized property.
|
||||
*/
|
||||
public static final Property DSA_DEFAULT_PARAMS = new Property("dsaDefaultParams", DSAParameters.class);
|
||||
private final String name;
|
||||
private final Class type;
|
||||
|
||||
private Property(String name, Class type)
|
||||
{
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ThreadLocalSecureRandomProvider
|
||||
implements SecureRandomProvider
|
||||
{
|
||||
final ThreadLocal<SecureRandom> defaultRandoms = new ThreadLocal<SecureRandom>();
|
||||
|
||||
public SecureRandom get()
|
||||
{
|
||||
if (defaultRandoms.get() == null)
|
||||
{
|
||||
defaultRandoms.set(new SecureRandom());
|
||||
}
|
||||
|
||||
return defaultRandoms.get();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package org.bouncycastle.crypto;
|
||||
|
||||
/**
|
||||
* this exception is thrown if a buffer that is meant to have output
|
||||
* copied into it turns out to be too short, or if we've been given
|
||||
* insufficient input. In general this exception will get thrown rather
|
||||
* than an ArrayOutOfBounds exception.
|
||||
*/
|
||||
public class DataLengthException
|
||||
extends RuntimeCryptoException
|
||||
{
|
||||
/**
|
||||
* base constructor.
|
||||
*/
|
||||
public DataLengthException()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* create a DataLengthException with the given message.
|
||||
*
|
||||
* @param message the message to be carried with the exception.
|
||||
*/
|
||||
public DataLengthException(
|
||||
String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
}
|
51
router/java/src/org/bouncycastle/crypto/Digest.java
Normal file
51
router/java/src/org/bouncycastle/crypto/Digest.java
Normal file
@ -0,0 +1,51 @@
|
||||
package org.bouncycastle.crypto;
|
||||
|
||||
/**
|
||||
* interface that a message digest conforms to.
|
||||
*/
|
||||
public interface Digest
|
||||
{
|
||||
/**
|
||||
* return the algorithm name
|
||||
*
|
||||
* @return the algorithm name
|
||||
*/
|
||||
public String getAlgorithmName();
|
||||
|
||||
/**
|
||||
* return the size, in bytes, of the digest produced by this message digest.
|
||||
*
|
||||
* @return the size, in bytes, of the digest produced by this message digest.
|
||||
*/
|
||||
public int getDigestSize();
|
||||
|
||||
/**
|
||||
* update the message digest with a single byte.
|
||||
*
|
||||
* @param in the input byte to be entered.
|
||||
*/
|
||||
public void update(byte in);
|
||||
|
||||
/**
|
||||
* update the message digest with a block of bytes.
|
||||
*
|
||||
* @param in the byte array containing the data.
|
||||
* @param inOff the offset into the byte array where the data starts.
|
||||
* @param len the length of the data.
|
||||
*/
|
||||
public void update(byte[] in, int inOff, int len);
|
||||
|
||||
/**
|
||||
* close the digest, producing the final digest value. The doFinal
|
||||
* call leaves the digest reset.
|
||||
*
|
||||
* @param out the array the digest is to be copied into.
|
||||
* @param outOff the offset into the out array the digest is to start at.
|
||||
*/
|
||||
public int doFinal(byte[] out, int outOff);
|
||||
|
||||
/**
|
||||
* reset the digest back to it's initial state.
|
||||
*/
|
||||
public void reset();
|
||||
}
|
13
router/java/src/org/bouncycastle/crypto/ExtendedDigest.java
Normal file
13
router/java/src/org/bouncycastle/crypto/ExtendedDigest.java
Normal file
@ -0,0 +1,13 @@
|
||||
package org.bouncycastle.crypto;
|
||||
|
||||
public interface ExtendedDigest
|
||||
extends Digest
|
||||
{
|
||||
/**
|
||||
* Return the size in bytes of the internal buffer the digest applies it's compression
|
||||
* function to.
|
||||
*
|
||||
* @return byte length of the digests internal buffer.
|
||||
*/
|
||||
public int getByteLength();
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package org.bouncycastle.crypto;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
|
||||
/**
|
||||
* The base class for parameters to key generators.
|
||||
*/
|
||||
public class KeyGenerationParameters
|
||||
{
|
||||
private SecureRandom random;
|
||||
private int strength;
|
||||
|
||||
/**
|
||||
* initialise the generator with a source of randomness
|
||||
* and a strength (in bits).
|
||||
*
|
||||
* @param random the random byte source.
|
||||
* @param strength the size, in bits, of the keys we want to produce.
|
||||
*/
|
||||
public KeyGenerationParameters(
|
||||
SecureRandom random,
|
||||
int strength)
|
||||
{
|
||||
this.random = CryptoServicesRegistrar.getSecureRandom(random);
|
||||
this.strength = strength;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the random source associated with this
|
||||
* generator.
|
||||
*
|
||||
* @return the generators random source.
|
||||
*/
|
||||
public SecureRandom getRandom()
|
||||
{
|
||||
return random;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the bit strength for keys produced by this generator,
|
||||
*
|
||||
* @return the strength of the keys this generator produces (in bits).
|
||||
*/
|
||||
public int getStrength()
|
||||
{
|
||||
return strength;
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package org.bouncycastle.crypto;
|
||||
|
||||
/**
|
||||
* the foundation class for the exceptions thrown by the crypto packages.
|
||||
*/
|
||||
public class RuntimeCryptoException
|
||||
extends RuntimeException
|
||||
{
|
||||
/**
|
||||
* base constructor.
|
||||
*/
|
||||
public RuntimeCryptoException()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* create a RuntimeCryptoException with the given message.
|
||||
*
|
||||
* @param message the message to be carried with the exception.
|
||||
*/
|
||||
public RuntimeCryptoException(
|
||||
String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package org.bouncycastle.crypto;
|
||||
|
||||
import javax.security.auth.Destroyable;
|
||||
|
||||
/**
|
||||
* Interface describing secret with encapsulation details.
|
||||
*/
|
||||
public interface SecretWithEncapsulation
|
||||
extends Destroyable
|
||||
{
|
||||
/**
|
||||
* Return the secret associated with the encapsulation.
|
||||
*
|
||||
* @return the secret the encapsulation is for.
|
||||
*/
|
||||
byte[] getSecret();
|
||||
|
||||
/**
|
||||
* Return the data that carries the secret in its encapsulated form.
|
||||
*
|
||||
* @return the encapsulation of the secret.
|
||||
*/
|
||||
byte[] getEncapsulation();
|
||||
}
|
30
router/java/src/org/bouncycastle/crypto/Xof.java
Normal file
30
router/java/src/org/bouncycastle/crypto/Xof.java
Normal file
@ -0,0 +1,30 @@
|
||||
package org.bouncycastle.crypto;
|
||||
|
||||
/**
|
||||
* With FIPS PUB 202 a new kind of message digest was announced which supported extendable output, or variable digest sizes.
|
||||
* This interface provides the extra method required to support variable output on an extended digest implementation.
|
||||
*/
|
||||
public interface Xof
|
||||
extends ExtendedDigest
|
||||
{
|
||||
/**
|
||||
* Output the results of the final calculation for this digest to outLen number of bytes.
|
||||
*
|
||||
* @param out output array to write the output bytes to.
|
||||
* @param outOff offset to start writing the bytes at.
|
||||
* @param outLen the number of output bytes requested.
|
||||
* @return the number of bytes written
|
||||
*/
|
||||
int doFinal(byte[] out, int outOff, int outLen);
|
||||
|
||||
/**
|
||||
* Start outputting the results of the final calculation for this digest. Unlike doFinal, this method
|
||||
* will continue producing output until the Xof is explicitly reset, or signals otherwise.
|
||||
*
|
||||
* @param out output array to write the output bytes to.
|
||||
* @param outOff offset to start writing the bytes at.
|
||||
* @param outLen the number of output bytes requested.
|
||||
* @return the number of bytes written
|
||||
*/
|
||||
int doOutput(byte[] out, int outOff, int outLen);
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package org.bouncycastle.crypto.digests;
|
||||
|
||||
/**
|
||||
* Encodable digests allow you to download an encoded copy of their internal state. This is useful for the situation where
|
||||
* you need to generate a signature on an external device and it allows for "sign with last round", so a copy of the
|
||||
* internal state of the digest, plus the last few blocks of the message are all that needs to be sent, rather than the
|
||||
* entire message.
|
||||
*/
|
||||
public interface EncodableDigest
|
||||
{
|
||||
/**
|
||||
* Return an encoded byte array for the digest's internal state
|
||||
*
|
||||
* @return an encoding of the digests internal state.
|
||||
*/
|
||||
byte[] getEncodedState();
|
||||
}
|
@ -0,0 +1,443 @@
|
||||
package org.bouncycastle.crypto.digests;
|
||||
|
||||
import org.bouncycastle.crypto.CryptoServiceProperties;
|
||||
import org.bouncycastle.crypto.CryptoServicePurpose;
|
||||
import org.bouncycastle.crypto.CryptoServicesRegistrar;
|
||||
import org.bouncycastle.crypto.ExtendedDigest;
|
||||
import org.bouncycastle.util.Arrays;
|
||||
import org.bouncycastle.util.Pack;
|
||||
|
||||
/**
|
||||
* implementation of Keccak based on following KeccakNISTInterface.c from https://keccak.noekeon.org/
|
||||
* <p>
|
||||
* Following the naming conventions used in the C source code to enable easy review of the implementation.
|
||||
*/
|
||||
public class KeccakDigest
|
||||
implements ExtendedDigest
|
||||
{
|
||||
private static long[] KeccakRoundConstants = new long[]{ 0x0000000000000001L, 0x0000000000008082L,
|
||||
0x800000000000808aL, 0x8000000080008000L, 0x000000000000808bL, 0x0000000080000001L, 0x8000000080008081L,
|
||||
0x8000000000008009L, 0x000000000000008aL, 0x0000000000000088L, 0x0000000080008009L, 0x000000008000000aL,
|
||||
0x000000008000808bL, 0x800000000000008bL, 0x8000000000008089L, 0x8000000000008003L, 0x8000000000008002L,
|
||||
0x8000000000000080L, 0x000000000000800aL, 0x800000008000000aL, 0x8000000080008081L, 0x8000000000008080L,
|
||||
0x0000000080000001L, 0x8000000080008008L };
|
||||
protected final CryptoServicePurpose purpose;
|
||||
|
||||
protected long[] state = new long[25];
|
||||
protected byte[] dataQueue = new byte[192];
|
||||
protected int rate;
|
||||
protected int bitsInQueue;
|
||||
protected int fixedOutputLength;
|
||||
protected boolean squeezing;
|
||||
|
||||
public KeccakDigest()
|
||||
{
|
||||
this(288, CryptoServicePurpose.ANY);
|
||||
}
|
||||
|
||||
public KeccakDigest(CryptoServicePurpose purpose)
|
||||
{
|
||||
this(288, purpose);
|
||||
}
|
||||
|
||||
public KeccakDigest(int bitLength)
|
||||
{
|
||||
this(bitLength, CryptoServicePurpose.ANY);
|
||||
}
|
||||
|
||||
public KeccakDigest(int bitLength, CryptoServicePurpose purpose)
|
||||
{
|
||||
this.purpose = purpose;
|
||||
init(bitLength);
|
||||
|
||||
CryptoServicesRegistrar.checkConstraints(cryptoServiceProperties());
|
||||
}
|
||||
|
||||
public KeccakDigest(KeccakDigest source)
|
||||
{
|
||||
this.purpose = source.purpose;
|
||||
System.arraycopy(source.state, 0, this.state, 0, source.state.length);
|
||||
System.arraycopy(source.dataQueue, 0, this.dataQueue, 0, source.dataQueue.length);
|
||||
this.rate = source.rate;
|
||||
this.bitsInQueue = source.bitsInQueue;
|
||||
this.fixedOutputLength = source.fixedOutputLength;
|
||||
this.squeezing = source.squeezing;
|
||||
|
||||
CryptoServicesRegistrar.checkConstraints(cryptoServiceProperties());
|
||||
}
|
||||
|
||||
public String getAlgorithmName()
|
||||
{
|
||||
return "Keccak-" + fixedOutputLength;
|
||||
}
|
||||
|
||||
public int getDigestSize()
|
||||
{
|
||||
return fixedOutputLength / 8;
|
||||
}
|
||||
|
||||
public void update(byte in)
|
||||
{
|
||||
absorb(in);
|
||||
}
|
||||
|
||||
public void update(byte[] in, int inOff, int len)
|
||||
{
|
||||
absorb(in, inOff, len);
|
||||
}
|
||||
|
||||
public int doFinal(byte[] out, int outOff)
|
||||
{
|
||||
squeeze(out, outOff, fixedOutputLength);
|
||||
|
||||
reset();
|
||||
|
||||
return getDigestSize();
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO Possible API change to support partial-byte suffixes.
|
||||
*/
|
||||
protected int doFinal(byte[] out, int outOff, byte partialByte, int partialBits)
|
||||
{
|
||||
if (partialBits > 0)
|
||||
{
|
||||
absorbBits(partialByte, partialBits);
|
||||
}
|
||||
|
||||
squeeze(out, outOff, fixedOutputLength);
|
||||
|
||||
reset();
|
||||
|
||||
return getDigestSize();
|
||||
}
|
||||
|
||||
public void reset()
|
||||
{
|
||||
init(fixedOutputLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the size of block that the compression function is applied to in bytes.
|
||||
*
|
||||
* @return internal byte length of a block.
|
||||
*/
|
||||
public int getByteLength()
|
||||
{
|
||||
return rate / 8;
|
||||
}
|
||||
|
||||
private void init(int bitLength)
|
||||
{
|
||||
switch (bitLength)
|
||||
{
|
||||
case 128:
|
||||
case 224:
|
||||
case 256:
|
||||
case 288:
|
||||
case 384:
|
||||
case 512:
|
||||
initSponge(1600 - (bitLength << 1));
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("bitLength must be one of 128, 224, 256, 288, 384, or 512.");
|
||||
}
|
||||
}
|
||||
|
||||
private void initSponge(int rate)
|
||||
{
|
||||
if ((rate <= 0) || (rate >= 1600) || ((rate % 64) != 0))
|
||||
{
|
||||
throw new IllegalStateException("invalid rate value");
|
||||
}
|
||||
|
||||
this.rate = rate;
|
||||
for (int i = 0; i < state.length; ++i)
|
||||
{
|
||||
state[i] = 0L;
|
||||
}
|
||||
Arrays.fill(this.dataQueue, (byte)0);
|
||||
this.bitsInQueue = 0;
|
||||
this.squeezing = false;
|
||||
this.fixedOutputLength = (1600 - rate) / 2;
|
||||
}
|
||||
|
||||
protected void absorb(byte data)
|
||||
{
|
||||
if ((bitsInQueue % 8) != 0)
|
||||
{
|
||||
throw new IllegalStateException("attempt to absorb with odd length queue");
|
||||
}
|
||||
if (squeezing)
|
||||
{
|
||||
throw new IllegalStateException("attempt to absorb while squeezing");
|
||||
}
|
||||
|
||||
dataQueue[bitsInQueue >>> 3] = data;
|
||||
if ((bitsInQueue += 8) == rate)
|
||||
{
|
||||
KeccakAbsorb(dataQueue, 0);
|
||||
bitsInQueue = 0;
|
||||
}
|
||||
}
|
||||
|
||||
protected void absorb(byte[] data, int off, int len)
|
||||
{
|
||||
if ((bitsInQueue % 8) != 0)
|
||||
{
|
||||
throw new IllegalStateException("attempt to absorb with odd length queue");
|
||||
}
|
||||
if (squeezing)
|
||||
{
|
||||
throw new IllegalStateException("attempt to absorb while squeezing");
|
||||
}
|
||||
|
||||
int bytesInQueue = bitsInQueue >>> 3;
|
||||
int rateBytes = rate >>> 3;
|
||||
|
||||
int available = rateBytes - bytesInQueue;
|
||||
if (len < available)
|
||||
{
|
||||
System.arraycopy(data, off, dataQueue, bytesInQueue, len);
|
||||
this.bitsInQueue += len << 3;
|
||||
return;
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
if (bytesInQueue > 0)
|
||||
{
|
||||
System.arraycopy(data, off, dataQueue, bytesInQueue, available);
|
||||
count += available;
|
||||
KeccakAbsorb(dataQueue, 0);
|
||||
}
|
||||
|
||||
int remaining;
|
||||
while ((remaining = (len - count)) >= rateBytes)
|
||||
{
|
||||
KeccakAbsorb(data, off + count);
|
||||
count += rateBytes;
|
||||
}
|
||||
|
||||
System.arraycopy(data, off + count, dataQueue, 0, remaining);
|
||||
this.bitsInQueue = remaining << 3;
|
||||
}
|
||||
|
||||
protected void absorbBits(int data, int bits)
|
||||
{
|
||||
if (bits < 1 || bits > 7)
|
||||
{
|
||||
throw new IllegalArgumentException("'bits' must be in the range 1 to 7");
|
||||
}
|
||||
if ((bitsInQueue % 8) != 0)
|
||||
{
|
||||
throw new IllegalStateException("attempt to absorb with odd length queue");
|
||||
}
|
||||
if (squeezing)
|
||||
{
|
||||
throw new IllegalStateException("attempt to absorb while squeezing");
|
||||
}
|
||||
|
||||
int mask = (1 << bits) - 1;
|
||||
dataQueue[bitsInQueue >>> 3] = (byte)(data & mask);
|
||||
|
||||
// NOTE: After this, bitsInQueue is no longer a multiple of 8, so no more absorbs will work
|
||||
bitsInQueue += bits;
|
||||
}
|
||||
|
||||
private void padAndSwitchToSqueezingPhase()
|
||||
{
|
||||
dataQueue[bitsInQueue >>> 3] |= (byte)(1 << (bitsInQueue & 7));
|
||||
|
||||
if (++bitsInQueue == rate)
|
||||
{
|
||||
KeccakAbsorb(dataQueue, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
int full = bitsInQueue >>> 6, partial = bitsInQueue & 63;
|
||||
int off = 0;
|
||||
for (int i = 0; i < full; ++i)
|
||||
{
|
||||
state[i] ^= Pack.littleEndianToLong(dataQueue, off);
|
||||
off += 8;
|
||||
}
|
||||
|
||||
if (partial > 0)
|
||||
{
|
||||
long mask = (1L << partial) - 1L;
|
||||
state[full] ^= Pack.littleEndianToLong(dataQueue, off) & mask;
|
||||
}
|
||||
}
|
||||
|
||||
state[(rate - 1) >>> 6] ^= (1L << 63);
|
||||
|
||||
bitsInQueue = 0;
|
||||
squeezing = true;
|
||||
}
|
||||
|
||||
protected void squeeze(byte[] output, int offset, long outputLength)
|
||||
{
|
||||
if (!squeezing)
|
||||
{
|
||||
padAndSwitchToSqueezingPhase();
|
||||
}
|
||||
|
||||
if ((outputLength % 8) != 0)
|
||||
{
|
||||
throw new IllegalStateException("outputLength not a multiple of 8");
|
||||
}
|
||||
|
||||
long i = 0;
|
||||
while (i < outputLength)
|
||||
{
|
||||
if (bitsInQueue == 0)
|
||||
{
|
||||
KeccakExtract();
|
||||
}
|
||||
int partialBlock = (int)Math.min((long)bitsInQueue, outputLength - i);
|
||||
System.arraycopy(dataQueue, (rate - bitsInQueue) / 8, output, offset + (int)(i / 8), partialBlock / 8);
|
||||
bitsInQueue -= partialBlock;
|
||||
i += partialBlock;
|
||||
}
|
||||
}
|
||||
|
||||
private void KeccakAbsorb(byte[] data, int off)
|
||||
{
|
||||
// assert 0 == bitsInQueue || (dataQueue == data && 0 == off);
|
||||
|
||||
int count = rate >>> 6;
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
state[i] ^= Pack.littleEndianToLong(data, off);
|
||||
off += 8;
|
||||
}
|
||||
|
||||
KeccakPermutation();
|
||||
}
|
||||
|
||||
private void KeccakExtract()
|
||||
{
|
||||
// assert 0 == bitsInQueue;
|
||||
|
||||
KeccakPermutation();
|
||||
|
||||
Pack.longToLittleEndian(state, 0, rate >>> 6, dataQueue, 0);
|
||||
|
||||
this.bitsInQueue = rate;
|
||||
}
|
||||
|
||||
private void KeccakPermutation()
|
||||
{
|
||||
long[] A = state;
|
||||
|
||||
long a00 = A[ 0], a01 = A[ 1], a02 = A[ 2], a03 = A[ 3], a04 = A[ 4];
|
||||
long a05 = A[ 5], a06 = A[ 6], a07 = A[ 7], a08 = A[ 8], a09 = A[ 9];
|
||||
long a10 = A[10], a11 = A[11], a12 = A[12], a13 = A[13], a14 = A[14];
|
||||
long a15 = A[15], a16 = A[16], a17 = A[17], a18 = A[18], a19 = A[19];
|
||||
long a20 = A[20], a21 = A[21], a22 = A[22], a23 = A[23], a24 = A[24];
|
||||
|
||||
for (int i = 0; i < 24; i++)
|
||||
{
|
||||
// theta
|
||||
long c0 = a00 ^ a05 ^ a10 ^ a15 ^ a20;
|
||||
long c1 = a01 ^ a06 ^ a11 ^ a16 ^ a21;
|
||||
long c2 = a02 ^ a07 ^ a12 ^ a17 ^ a22;
|
||||
long c3 = a03 ^ a08 ^ a13 ^ a18 ^ a23;
|
||||
long c4 = a04 ^ a09 ^ a14 ^ a19 ^ a24;
|
||||
|
||||
long d1 = (c1 << 1 | c1 >>> -1) ^ c4;
|
||||
long d2 = (c2 << 1 | c2 >>> -1) ^ c0;
|
||||
long d3 = (c3 << 1 | c3 >>> -1) ^ c1;
|
||||
long d4 = (c4 << 1 | c4 >>> -1) ^ c2;
|
||||
long d0 = (c0 << 1 | c0 >>> -1) ^ c3;
|
||||
|
||||
a00 ^= d1; a05 ^= d1; a10 ^= d1; a15 ^= d1; a20 ^= d1;
|
||||
a01 ^= d2; a06 ^= d2; a11 ^= d2; a16 ^= d2; a21 ^= d2;
|
||||
a02 ^= d3; a07 ^= d3; a12 ^= d3; a17 ^= d3; a22 ^= d3;
|
||||
a03 ^= d4; a08 ^= d4; a13 ^= d4; a18 ^= d4; a23 ^= d4;
|
||||
a04 ^= d0; a09 ^= d0; a14 ^= d0; a19 ^= d0; a24 ^= d0;
|
||||
|
||||
// rho/pi
|
||||
c1 = a01 << 1 | a01 >>> 63;
|
||||
a01 = a06 << 44 | a06 >>> 20;
|
||||
a06 = a09 << 20 | a09 >>> 44;
|
||||
a09 = a22 << 61 | a22 >>> 3;
|
||||
a22 = a14 << 39 | a14 >>> 25;
|
||||
a14 = a20 << 18 | a20 >>> 46;
|
||||
a20 = a02 << 62 | a02 >>> 2;
|
||||
a02 = a12 << 43 | a12 >>> 21;
|
||||
a12 = a13 << 25 | a13 >>> 39;
|
||||
a13 = a19 << 8 | a19 >>> 56;
|
||||
a19 = a23 << 56 | a23 >>> 8;
|
||||
a23 = a15 << 41 | a15 >>> 23;
|
||||
a15 = a04 << 27 | a04 >>> 37;
|
||||
a04 = a24 << 14 | a24 >>> 50;
|
||||
a24 = a21 << 2 | a21 >>> 62;
|
||||
a21 = a08 << 55 | a08 >>> 9;
|
||||
a08 = a16 << 45 | a16 >>> 19;
|
||||
a16 = a05 << 36 | a05 >>> 28;
|
||||
a05 = a03 << 28 | a03 >>> 36;
|
||||
a03 = a18 << 21 | a18 >>> 43;
|
||||
a18 = a17 << 15 | a17 >>> 49;
|
||||
a17 = a11 << 10 | a11 >>> 54;
|
||||
a11 = a07 << 6 | a07 >>> 58;
|
||||
a07 = a10 << 3 | a10 >>> 61;
|
||||
a10 = c1;
|
||||
|
||||
// chi
|
||||
c0 = a00 ^ (~a01 & a02);
|
||||
c1 = a01 ^ (~a02 & a03);
|
||||
a02 ^= ~a03 & a04;
|
||||
a03 ^= ~a04 & a00;
|
||||
a04 ^= ~a00 & a01;
|
||||
a00 = c0;
|
||||
a01 = c1;
|
||||
|
||||
c0 = a05 ^ (~a06 & a07);
|
||||
c1 = a06 ^ (~a07 & a08);
|
||||
a07 ^= ~a08 & a09;
|
||||
a08 ^= ~a09 & a05;
|
||||
a09 ^= ~a05 & a06;
|
||||
a05 = c0;
|
||||
a06 = c1;
|
||||
|
||||
c0 = a10 ^ (~a11 & a12);
|
||||
c1 = a11 ^ (~a12 & a13);
|
||||
a12 ^= ~a13 & a14;
|
||||
a13 ^= ~a14 & a10;
|
||||
a14 ^= ~a10 & a11;
|
||||
a10 = c0;
|
||||
a11 = c1;
|
||||
|
||||
c0 = a15 ^ (~a16 & a17);
|
||||
c1 = a16 ^ (~a17 & a18);
|
||||
a17 ^= ~a18 & a19;
|
||||
a18 ^= ~a19 & a15;
|
||||
a19 ^= ~a15 & a16;
|
||||
a15 = c0;
|
||||
a16 = c1;
|
||||
|
||||
c0 = a20 ^ (~a21 & a22);
|
||||
c1 = a21 ^ (~a22 & a23);
|
||||
a22 ^= ~a23 & a24;
|
||||
a23 ^= ~a24 & a20;
|
||||
a24 ^= ~a20 & a21;
|
||||
a20 = c0;
|
||||
a21 = c1;
|
||||
|
||||
// iota
|
||||
a00 ^= KeccakRoundConstants[i];
|
||||
}
|
||||
|
||||
A[ 0] = a00; A[ 1] = a01; A[ 2] = a02; A[ 3] = a03; A[ 4] = a04;
|
||||
A[ 5] = a05; A[ 6] = a06; A[ 7] = a07; A[ 8] = a08; A[ 9] = a09;
|
||||
A[10] = a10; A[11] = a11; A[12] = a12; A[13] = a13; A[14] = a14;
|
||||
A[15] = a15; A[16] = a16; A[17] = a17; A[18] = a18; A[19] = a19;
|
||||
A[20] = a20; A[21] = a21; A[22] = a22; A[23] = a23; A[24] = a24;
|
||||
}
|
||||
|
||||
protected CryptoServiceProperties cryptoServiceProperties()
|
||||
{
|
||||
return Utils.getDefaultProperties(this, getDigestSize() * 8, purpose);
|
||||
}
|
||||
}
|
426
router/java/src/org/bouncycastle/crypto/digests/LongDigest.java
Normal file
426
router/java/src/org/bouncycastle/crypto/digests/LongDigest.java
Normal file
@ -0,0 +1,426 @@
|
||||
package org.bouncycastle.crypto.digests;
|
||||
|
||||
import org.bouncycastle.crypto.CryptoServiceProperties;
|
||||
import org.bouncycastle.crypto.CryptoServicePurpose;
|
||||
import org.bouncycastle.crypto.ExtendedDigest;
|
||||
import org.bouncycastle.util.Memoable;
|
||||
import org.bouncycastle.util.Pack;
|
||||
|
||||
/**
|
||||
* Base class for SHA-384 and SHA-512.
|
||||
*/
|
||||
public abstract class LongDigest
|
||||
implements ExtendedDigest, Memoable, EncodableDigest
|
||||
{
|
||||
private static final int BYTE_LENGTH = 128;
|
||||
|
||||
protected final CryptoServicePurpose purpose;
|
||||
|
||||
private byte[] xBuf = new byte[8];
|
||||
private int xBufOff;
|
||||
|
||||
private long byteCount1;
|
||||
private long byteCount2;
|
||||
|
||||
protected long H1, H2, H3, H4, H5, H6, H7, H8;
|
||||
|
||||
private long[] W = new long[80];
|
||||
private int wOff;
|
||||
|
||||
/**
|
||||
* Constructor for variable length word
|
||||
*/
|
||||
protected LongDigest()
|
||||
{
|
||||
this(CryptoServicePurpose.ANY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for variable length word
|
||||
*/
|
||||
protected LongDigest(CryptoServicePurpose purpose)
|
||||
{
|
||||
this.purpose = purpose;
|
||||
|
||||
xBufOff = 0;
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor. We are using copy constructors in place
|
||||
* of the Object.clone() interface as this interface is not
|
||||
* supported by J2ME.
|
||||
*/
|
||||
protected LongDigest(LongDigest t)
|
||||
{
|
||||
this.purpose = t.purpose;
|
||||
|
||||
copyIn(t);
|
||||
}
|
||||
|
||||
protected void copyIn(LongDigest t)
|
||||
{
|
||||
System.arraycopy(t.xBuf, 0, xBuf, 0, t.xBuf.length);
|
||||
|
||||
xBufOff = t.xBufOff;
|
||||
byteCount1 = t.byteCount1;
|
||||
byteCount2 = t.byteCount2;
|
||||
|
||||
H1 = t.H1;
|
||||
H2 = t.H2;
|
||||
H3 = t.H3;
|
||||
H4 = t.H4;
|
||||
H5 = t.H5;
|
||||
H6 = t.H6;
|
||||
H7 = t.H7;
|
||||
H8 = t.H8;
|
||||
|
||||
System.arraycopy(t.W, 0, W, 0, t.W.length);
|
||||
wOff = t.wOff;
|
||||
}
|
||||
|
||||
protected void populateState(byte[] state)
|
||||
{
|
||||
System.arraycopy(xBuf, 0, state, 0, xBufOff);
|
||||
Pack.intToBigEndian(xBufOff, state, 8);
|
||||
Pack.longToBigEndian(byteCount1, state, 12);
|
||||
Pack.longToBigEndian(byteCount2, state, 20);
|
||||
Pack.longToBigEndian(H1, state, 28);
|
||||
Pack.longToBigEndian(H2, state, 36);
|
||||
Pack.longToBigEndian(H3, state, 44);
|
||||
Pack.longToBigEndian(H4, state, 52);
|
||||
Pack.longToBigEndian(H5, state, 60);
|
||||
Pack.longToBigEndian(H6, state, 68);
|
||||
Pack.longToBigEndian(H7, state, 76);
|
||||
Pack.longToBigEndian(H8, state, 84);
|
||||
|
||||
Pack.intToBigEndian(wOff, state, 92);
|
||||
for (int i = 0; i < wOff; i++)
|
||||
{
|
||||
Pack.longToBigEndian(W[i], state, 96 + (i * 8));
|
||||
}
|
||||
}
|
||||
|
||||
protected void restoreState(byte[] encodedState)
|
||||
{
|
||||
xBufOff = Pack.bigEndianToInt(encodedState, 8);
|
||||
System.arraycopy(encodedState, 0, xBuf, 0, xBufOff);
|
||||
byteCount1 = Pack.bigEndianToLong(encodedState, 12);
|
||||
byteCount2 = Pack.bigEndianToLong(encodedState, 20);
|
||||
|
||||
H1 = Pack.bigEndianToLong(encodedState, 28);
|
||||
H2 = Pack.bigEndianToLong(encodedState, 36);
|
||||
H3 = Pack.bigEndianToLong(encodedState, 44);
|
||||
H4 = Pack.bigEndianToLong(encodedState, 52);
|
||||
H5 = Pack.bigEndianToLong(encodedState, 60);
|
||||
H6 = Pack.bigEndianToLong(encodedState, 68);
|
||||
H7 = Pack.bigEndianToLong(encodedState, 76);
|
||||
H8 = Pack.bigEndianToLong(encodedState, 84);
|
||||
|
||||
wOff = Pack.bigEndianToInt(encodedState, 92);
|
||||
for (int i = 0; i < wOff; i++)
|
||||
{
|
||||
W[i] = Pack.bigEndianToLong(encodedState, 96 + (i * 8));
|
||||
}
|
||||
}
|
||||
|
||||
protected int getEncodedStateSize()
|
||||
{
|
||||
return 96 + (wOff * 8);
|
||||
}
|
||||
|
||||
public void update(
|
||||
byte in)
|
||||
{
|
||||
xBuf[xBufOff++] = in;
|
||||
|
||||
if (xBufOff == xBuf.length)
|
||||
{
|
||||
processWord(xBuf, 0);
|
||||
xBufOff = 0;
|
||||
}
|
||||
|
||||
byteCount1++;
|
||||
}
|
||||
|
||||
public void update(
|
||||
byte[] in,
|
||||
int inOff,
|
||||
int len)
|
||||
{
|
||||
//
|
||||
// fill the current word
|
||||
//
|
||||
while ((xBufOff != 0) && (len > 0))
|
||||
{
|
||||
update(in[inOff]);
|
||||
|
||||
inOff++;
|
||||
len--;
|
||||
}
|
||||
|
||||
//
|
||||
// process whole words.
|
||||
//
|
||||
while (len >= xBuf.length)
|
||||
{
|
||||
processWord(in, inOff);
|
||||
|
||||
inOff += xBuf.length;
|
||||
len -= xBuf.length;
|
||||
byteCount1 += xBuf.length;
|
||||
}
|
||||
|
||||
//
|
||||
// load in the remainder.
|
||||
//
|
||||
while (len > 0)
|
||||
{
|
||||
update(in[inOff]);
|
||||
|
||||
inOff++;
|
||||
len--;
|
||||
}
|
||||
}
|
||||
|
||||
public void finish()
|
||||
{
|
||||
adjustByteCounts();
|
||||
|
||||
long lowBitLength = byteCount1 << 3;
|
||||
long hiBitLength = byteCount2;
|
||||
|
||||
//
|
||||
// add the pad bytes.
|
||||
//
|
||||
update((byte)128);
|
||||
|
||||
while (xBufOff != 0)
|
||||
{
|
||||
update((byte)0);
|
||||
}
|
||||
|
||||
processLength(lowBitLength, hiBitLength);
|
||||
|
||||
processBlock();
|
||||
}
|
||||
|
||||
public void reset()
|
||||
{
|
||||
byteCount1 = 0;
|
||||
byteCount2 = 0;
|
||||
|
||||
xBufOff = 0;
|
||||
for (int i = 0; i < xBuf.length; i++)
|
||||
{
|
||||
xBuf[i] = 0;
|
||||
}
|
||||
|
||||
wOff = 0;
|
||||
for (int i = 0; i != W.length; i++)
|
||||
{
|
||||
W[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public int getByteLength()
|
||||
{
|
||||
return BYTE_LENGTH;
|
||||
}
|
||||
|
||||
protected void processWord(
|
||||
byte[] in,
|
||||
int inOff)
|
||||
{
|
||||
W[wOff] = Pack.bigEndianToLong(in, inOff);
|
||||
|
||||
if (++wOff == 16)
|
||||
{
|
||||
processBlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* adjust the byte counts so that byteCount2 represents the
|
||||
* upper long (less 3 bits) word of the byte count.
|
||||
*/
|
||||
private void adjustByteCounts()
|
||||
{
|
||||
if (byteCount1 > 0x1fffffffffffffffL)
|
||||
{
|
||||
byteCount2 += (byteCount1 >>> 61);
|
||||
byteCount1 &= 0x1fffffffffffffffL;
|
||||
}
|
||||
}
|
||||
|
||||
protected void processLength(
|
||||
long lowW,
|
||||
long hiW)
|
||||
{
|
||||
if (wOff > 14)
|
||||
{
|
||||
processBlock();
|
||||
}
|
||||
|
||||
W[14] = hiW;
|
||||
W[15] = lowW;
|
||||
}
|
||||
|
||||
protected void processBlock()
|
||||
{
|
||||
adjustByteCounts();
|
||||
|
||||
//
|
||||
// expand 16 word block into 80 word blocks.
|
||||
//
|
||||
for (int t = 16; t <= 79; t++)
|
||||
{
|
||||
W[t] = Sigma1(W[t - 2]) + W[t - 7] + Sigma0(W[t - 15]) + W[t - 16];
|
||||
}
|
||||
|
||||
//
|
||||
// set up working variables.
|
||||
//
|
||||
long a = H1;
|
||||
long b = H2;
|
||||
long c = H3;
|
||||
long d = H4;
|
||||
long e = H5;
|
||||
long f = H6;
|
||||
long g = H7;
|
||||
long h = H8;
|
||||
|
||||
int t = 0;
|
||||
for(int i = 0; i < 10; i ++)
|
||||
{
|
||||
// t = 8 * i
|
||||
h += Sum1(e) + Ch(e, f, g) + K[t] + W[t++];
|
||||
d += h;
|
||||
h += Sum0(a) + Maj(a, b, c);
|
||||
|
||||
// t = 8 * i + 1
|
||||
g += Sum1(d) + Ch(d, e, f) + K[t] + W[t++];
|
||||
c += g;
|
||||
g += Sum0(h) + Maj(h, a, b);
|
||||
|
||||
// t = 8 * i + 2
|
||||
f += Sum1(c) + Ch(c, d, e) + K[t] + W[t++];
|
||||
b += f;
|
||||
f += Sum0(g) + Maj(g, h, a);
|
||||
|
||||
// t = 8 * i + 3
|
||||
e += Sum1(b) + Ch(b, c, d) + K[t] + W[t++];
|
||||
a += e;
|
||||
e += Sum0(f) + Maj(f, g, h);
|
||||
|
||||
// t = 8 * i + 4
|
||||
d += Sum1(a) + Ch(a, b, c) + K[t] + W[t++];
|
||||
h += d;
|
||||
d += Sum0(e) + Maj(e, f, g);
|
||||
|
||||
// t = 8 * i + 5
|
||||
c += Sum1(h) + Ch(h, a, b) + K[t] + W[t++];
|
||||
g += c;
|
||||
c += Sum0(d) + Maj(d, e, f);
|
||||
|
||||
// t = 8 * i + 6
|
||||
b += Sum1(g) + Ch(g, h, a) + K[t] + W[t++];
|
||||
f += b;
|
||||
b += Sum0(c) + Maj(c, d, e);
|
||||
|
||||
// t = 8 * i + 7
|
||||
a += Sum1(f) + Ch(f, g, h) + K[t] + W[t++];
|
||||
e += a;
|
||||
a += Sum0(b) + Maj(b, c, d);
|
||||
}
|
||||
|
||||
H1 += a;
|
||||
H2 += b;
|
||||
H3 += c;
|
||||
H4 += d;
|
||||
H5 += e;
|
||||
H6 += f;
|
||||
H7 += g;
|
||||
H8 += h;
|
||||
|
||||
//
|
||||
// reset the offset and clean out the word buffer.
|
||||
//
|
||||
wOff = 0;
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
W[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* SHA-384 and SHA-512 functions (as for SHA-256 but for longs) */
|
||||
private long Ch(
|
||||
long x,
|
||||
long y,
|
||||
long z)
|
||||
{
|
||||
return ((x & y) ^ ((~x) & z));
|
||||
}
|
||||
|
||||
private long Maj(
|
||||
long x,
|
||||
long y,
|
||||
long z)
|
||||
{
|
||||
return ((x & y) ^ (x & z) ^ (y & z));
|
||||
}
|
||||
|
||||
private long Sum0(
|
||||
long x)
|
||||
{
|
||||
return ((x << 36)|(x >>> 28)) ^ ((x << 30)|(x >>> 34)) ^ ((x << 25)|(x >>> 39));
|
||||
}
|
||||
|
||||
private long Sum1(
|
||||
long x)
|
||||
{
|
||||
return ((x << 50)|(x >>> 14)) ^ ((x << 46)|(x >>> 18)) ^ ((x << 23)|(x >>> 41));
|
||||
}
|
||||
|
||||
private long Sigma0(
|
||||
long x)
|
||||
{
|
||||
return ((x << 63)|(x >>> 1)) ^ ((x << 56)|(x >>> 8)) ^ (x >>> 7);
|
||||
}
|
||||
|
||||
private long Sigma1(
|
||||
long x)
|
||||
{
|
||||
return ((x << 45)|(x >>> 19)) ^ ((x << 3)|(x >>> 61)) ^ (x >>> 6);
|
||||
}
|
||||
|
||||
/* SHA-384 and SHA-512 Constants
|
||||
* (represent the first 64 bits of the fractional parts of the
|
||||
* cube roots of the first sixty-four prime numbers)
|
||||
*/
|
||||
static final long K[] = {
|
||||
0x428a2f98d728ae22L, 0x7137449123ef65cdL, 0xb5c0fbcfec4d3b2fL, 0xe9b5dba58189dbbcL,
|
||||
0x3956c25bf348b538L, 0x59f111f1b605d019L, 0x923f82a4af194f9bL, 0xab1c5ed5da6d8118L,
|
||||
0xd807aa98a3030242L, 0x12835b0145706fbeL, 0x243185be4ee4b28cL, 0x550c7dc3d5ffb4e2L,
|
||||
0x72be5d74f27b896fL, 0x80deb1fe3b1696b1L, 0x9bdc06a725c71235L, 0xc19bf174cf692694L,
|
||||
0xe49b69c19ef14ad2L, 0xefbe4786384f25e3L, 0x0fc19dc68b8cd5b5L, 0x240ca1cc77ac9c65L,
|
||||
0x2de92c6f592b0275L, 0x4a7484aa6ea6e483L, 0x5cb0a9dcbd41fbd4L, 0x76f988da831153b5L,
|
||||
0x983e5152ee66dfabL, 0xa831c66d2db43210L, 0xb00327c898fb213fL, 0xbf597fc7beef0ee4L,
|
||||
0xc6e00bf33da88fc2L, 0xd5a79147930aa725L, 0x06ca6351e003826fL, 0x142929670a0e6e70L,
|
||||
0x27b70a8546d22ffcL, 0x2e1b21385c26c926L, 0x4d2c6dfc5ac42aedL, 0x53380d139d95b3dfL,
|
||||
0x650a73548baf63deL, 0x766a0abb3c77b2a8L, 0x81c2c92e47edaee6L, 0x92722c851482353bL,
|
||||
0xa2bfe8a14cf10364L, 0xa81a664bbc423001L, 0xc24b8b70d0f89791L, 0xc76c51a30654be30L,
|
||||
0xd192e819d6ef5218L, 0xd69906245565a910L, 0xf40e35855771202aL, 0x106aa07032bbd1b8L,
|
||||
0x19a4c116b8d2d0c8L, 0x1e376c085141ab53L, 0x2748774cdf8eeb99L, 0x34b0bcb5e19b48a8L,
|
||||
0x391c0cb3c5c95a63L, 0x4ed8aa4ae3418acbL, 0x5b9cca4f7763e373L, 0x682e6ff3d6b2b8a3L,
|
||||
0x748f82ee5defb2fcL, 0x78a5636f43172f60L, 0x84c87814a1f0ab72L, 0x8cc702081a6439ecL,
|
||||
0x90befffa23631e28L, 0xa4506cebde82bde9L, 0xbef9a3f7b2c67915L, 0xc67178f2e372532bL,
|
||||
0xca273eceea26619cL, 0xd186b8c721c0c207L, 0xeada7dd6cde0eb1eL, 0xf57d4f7fee6ed178L,
|
||||
0x06f067aa72176fbaL, 0x0a637dc5a2c898a6L, 0x113f9804bef90daeL, 0x1b710b35131c471bL,
|
||||
0x28db77f523047d84L, 0x32caab7b40c72493L, 0x3c9ebe0a15c9bebcL, 0x431d67c49c100d4cL,
|
||||
0x4cc5d4becb3e42b6L, 0x597f299cfc657e2aL, 0x5fcb6fab3ad6faecL, 0x6c44198c4a475817L
|
||||
};
|
||||
|
||||
protected abstract CryptoServiceProperties cryptoServiceProperties();
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
package org.bouncycastle.crypto.digests;
|
||||
|
||||
|
||||
import org.bouncycastle.crypto.CryptoServicePurpose;
|
||||
|
||||
/**
|
||||
* implementation of SHA-3 based on following KeccakNISTInterface.c from https://keccak.noekeon.org/
|
||||
* <p>
|
||||
* Following the naming conventions used in the C source code to enable easy review of the implementation.
|
||||
*/
|
||||
public class SHA3Digest
|
||||
extends KeccakDigest
|
||||
{
|
||||
private static int checkBitLength(int bitLength)
|
||||
{
|
||||
switch (bitLength)
|
||||
{
|
||||
case 224:
|
||||
case 256:
|
||||
case 384:
|
||||
case 512:
|
||||
return bitLength;
|
||||
default:
|
||||
throw new IllegalArgumentException("'bitLength' " + bitLength + " not supported for SHA-3");
|
||||
}
|
||||
}
|
||||
|
||||
public SHA3Digest()
|
||||
{
|
||||
this(256, CryptoServicePurpose.ANY);
|
||||
}
|
||||
|
||||
public SHA3Digest(CryptoServicePurpose purpose)
|
||||
{
|
||||
this(256, purpose);
|
||||
}
|
||||
|
||||
public SHA3Digest(int bitLength)
|
||||
{
|
||||
super(checkBitLength(bitLength), CryptoServicePurpose.ANY);
|
||||
}
|
||||
|
||||
public SHA3Digest(int bitLength, CryptoServicePurpose purpose)
|
||||
{
|
||||
super(checkBitLength(bitLength), purpose);
|
||||
}
|
||||
|
||||
public SHA3Digest(SHA3Digest source)
|
||||
{
|
||||
super(source);
|
||||
}
|
||||
|
||||
public String getAlgorithmName()
|
||||
{
|
||||
return "SHA3-" + fixedOutputLength;
|
||||
}
|
||||
|
||||
public int doFinal(byte[] out, int outOff)
|
||||
{
|
||||
absorbBits(0x02, 2);
|
||||
|
||||
return super.doFinal(out, outOff);
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO Possible API change to support partial-byte suffixes.
|
||||
*/
|
||||
protected int doFinal(byte[] out, int outOff, byte partialByte, int partialBits)
|
||||
{
|
||||
if (partialBits < 0 || partialBits > 7)
|
||||
{
|
||||
throw new IllegalArgumentException("'partialBits' must be in the range [0,7]");
|
||||
}
|
||||
|
||||
int finalInput = (partialByte & ((1 << partialBits) - 1)) | (0x02 << partialBits);
|
||||
int finalBits = partialBits + 2;
|
||||
|
||||
if (finalBits >= 8)
|
||||
{
|
||||
absorb((byte)finalInput);
|
||||
finalBits -= 8;
|
||||
finalInput >>>= 8;
|
||||
}
|
||||
|
||||
return super.doFinal(out, outOff, (byte)finalInput, finalBits);
|
||||
}
|
||||
}
|
@ -0,0 +1,149 @@
|
||||
package org.bouncycastle.crypto.digests;
|
||||
|
||||
import org.bouncycastle.crypto.CryptoServiceProperties;
|
||||
import org.bouncycastle.crypto.CryptoServicePurpose;
|
||||
import org.bouncycastle.crypto.CryptoServicesRegistrar;
|
||||
import org.bouncycastle.util.Memoable;
|
||||
import org.bouncycastle.util.Pack;
|
||||
|
||||
|
||||
/**
|
||||
* FIPS 180-2 implementation of SHA-512.
|
||||
*
|
||||
* <pre>
|
||||
* block word digest
|
||||
* SHA-1 512 32 160
|
||||
* SHA-256 512 32 256
|
||||
* SHA-384 1024 64 384
|
||||
* SHA-512 1024 64 512
|
||||
* </pre>
|
||||
*/
|
||||
public class SHA512Digest
|
||||
extends LongDigest
|
||||
{
|
||||
private static final int DIGEST_LENGTH = 64;
|
||||
|
||||
/**
|
||||
* Standard constructor
|
||||
*/
|
||||
public SHA512Digest()
|
||||
{
|
||||
this(CryptoServicePurpose.ANY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard constructor, with purpose
|
||||
*/
|
||||
public SHA512Digest(CryptoServicePurpose purpose)
|
||||
{
|
||||
super(purpose);
|
||||
|
||||
CryptoServicesRegistrar.checkConstraints(cryptoServiceProperties());
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor. This will copy the state of the provided
|
||||
* message digest.
|
||||
*/
|
||||
public SHA512Digest(SHA512Digest t)
|
||||
{
|
||||
super(t);
|
||||
|
||||
CryptoServicesRegistrar.checkConstraints(cryptoServiceProperties());
|
||||
}
|
||||
|
||||
/**
|
||||
* State constructor - create a digest initialised with the state of a previous one.
|
||||
*
|
||||
* @param encodedState the encoded state from the originating digest.
|
||||
*/
|
||||
public SHA512Digest(byte[] encodedState)
|
||||
{
|
||||
super(CryptoServicePurpose.values()[encodedState[encodedState.length - 1]]);
|
||||
|
||||
restoreState(encodedState);
|
||||
|
||||
CryptoServicesRegistrar.checkConstraints(cryptoServiceProperties());
|
||||
}
|
||||
|
||||
public String getAlgorithmName()
|
||||
{
|
||||
return "SHA-512";
|
||||
}
|
||||
|
||||
public int getDigestSize()
|
||||
{
|
||||
return DIGEST_LENGTH;
|
||||
}
|
||||
|
||||
public int doFinal(
|
||||
byte[] out,
|
||||
int outOff)
|
||||
{
|
||||
finish();
|
||||
|
||||
Pack.longToBigEndian(H1, out, outOff);
|
||||
Pack.longToBigEndian(H2, out, outOff + 8);
|
||||
Pack.longToBigEndian(H3, out, outOff + 16);
|
||||
Pack.longToBigEndian(H4, out, outOff + 24);
|
||||
Pack.longToBigEndian(H5, out, outOff + 32);
|
||||
Pack.longToBigEndian(H6, out, outOff + 40);
|
||||
Pack.longToBigEndian(H7, out, outOff + 48);
|
||||
Pack.longToBigEndian(H8, out, outOff + 56);
|
||||
|
||||
reset();
|
||||
|
||||
return DIGEST_LENGTH;
|
||||
}
|
||||
|
||||
/**
|
||||
* reset the chaining variables
|
||||
*/
|
||||
public void reset()
|
||||
{
|
||||
super.reset();
|
||||
|
||||
/* SHA-512 initial hash value
|
||||
* The first 64 bits of the fractional parts of the square roots
|
||||
* of the first eight prime numbers
|
||||
*/
|
||||
H1 = 0x6a09e667f3bcc908L;
|
||||
H2 = 0xbb67ae8584caa73bL;
|
||||
H3 = 0x3c6ef372fe94f82bL;
|
||||
H4 = 0xa54ff53a5f1d36f1L;
|
||||
H5 = 0x510e527fade682d1L;
|
||||
H6 = 0x9b05688c2b3e6c1fL;
|
||||
H7 = 0x1f83d9abfb41bd6bL;
|
||||
H8 = 0x5be0cd19137e2179L;
|
||||
}
|
||||
|
||||
public Memoable copy()
|
||||
{
|
||||
return new SHA512Digest(this);
|
||||
}
|
||||
|
||||
public void reset(Memoable other)
|
||||
{
|
||||
SHA512Digest d = (SHA512Digest)other;
|
||||
|
||||
copyIn(d);
|
||||
}
|
||||
|
||||
public byte[] getEncodedState()
|
||||
{
|
||||
byte[] encoded = new byte[getEncodedStateSize() + 1];
|
||||
super.populateState(encoded);
|
||||
|
||||
encoded[encoded.length - 1] = (byte)purpose.ordinal();
|
||||
|
||||
return encoded;
|
||||
}
|
||||
|
||||
protected CryptoServiceProperties cryptoServiceProperties()
|
||||
{
|
||||
return Utils.getDefaultProperties(this, 256, purpose);
|
||||
}
|
||||
}
|
||||
|
150
router/java/src/org/bouncycastle/crypto/digests/SHAKEDigest.java
Normal file
150
router/java/src/org/bouncycastle/crypto/digests/SHAKEDigest.java
Normal file
@ -0,0 +1,150 @@
|
||||
package org.bouncycastle.crypto.digests;
|
||||
|
||||
import org.bouncycastle.crypto.CryptoServiceProperties;
|
||||
import org.bouncycastle.crypto.CryptoServicePurpose;
|
||||
import org.bouncycastle.crypto.Xof;
|
||||
|
||||
|
||||
/**
|
||||
* implementation of SHAKE based on following KeccakNISTInterface.c from https://keccak.noekeon.org/
|
||||
* <p>
|
||||
* Following the naming conventions used in the C source code to enable easy review of the implementation.
|
||||
*/
|
||||
public class SHAKEDigest
|
||||
extends KeccakDigest
|
||||
implements Xof
|
||||
{
|
||||
private static int checkBitLength(int bitStrength)
|
||||
{
|
||||
switch (bitStrength)
|
||||
{
|
||||
case 128:
|
||||
case 256:
|
||||
return bitStrength;
|
||||
default:
|
||||
throw new IllegalArgumentException("'bitStrength' " + bitStrength + " not supported for SHAKE");
|
||||
}
|
||||
}
|
||||
|
||||
public SHAKEDigest()
|
||||
{
|
||||
this(128);
|
||||
}
|
||||
|
||||
public SHAKEDigest(CryptoServicePurpose purpose)
|
||||
{
|
||||
this(128, purpose);
|
||||
}
|
||||
|
||||
/**
|
||||
* Base constructor.
|
||||
*
|
||||
* @param bitStrength the security strength in bits of the XOF.
|
||||
*/
|
||||
public SHAKEDigest(int bitStrength)
|
||||
{
|
||||
super(checkBitLength(bitStrength), CryptoServicePurpose.ANY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Base constructor.
|
||||
*
|
||||
* @param bitStrength the security strength in bits of the XOF.
|
||||
* @param purpose the purpose of the digest will be used for.
|
||||
*/
|
||||
public SHAKEDigest(int bitStrength, CryptoServicePurpose purpose)
|
||||
{
|
||||
super(checkBitLength(bitStrength), purpose);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone constructor
|
||||
*
|
||||
* @param source the other digest to be copied.
|
||||
*/
|
||||
public SHAKEDigest(SHAKEDigest source)
|
||||
{
|
||||
super(source);
|
||||
}
|
||||
|
||||
public String getAlgorithmName()
|
||||
{
|
||||
return "SHAKE" + fixedOutputLength;
|
||||
}
|
||||
|
||||
public int getDigestSize()
|
||||
{
|
||||
return fixedOutputLength / 4;
|
||||
}
|
||||
|
||||
public int doFinal(byte[] out, int outOff)
|
||||
{
|
||||
return doFinal(out, outOff, getDigestSize());
|
||||
}
|
||||
|
||||
public int doFinal(byte[] out, int outOff, int outLen)
|
||||
{
|
||||
int length = doOutput(out, outOff, outLen);
|
||||
|
||||
reset();
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
public int doOutput(byte[] out, int outOff, int outLen)
|
||||
{
|
||||
if (!squeezing)
|
||||
{
|
||||
absorbBits(0x0F, 4);
|
||||
}
|
||||
|
||||
squeeze(out, outOff, ((long)outLen) * 8);
|
||||
|
||||
return outLen;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO Possible API change to support partial-byte suffixes.
|
||||
*/
|
||||
protected int doFinal(byte[] out, int outOff, byte partialByte, int partialBits)
|
||||
{
|
||||
return doFinal(out, outOff, getDigestSize(), partialByte, partialBits);
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO Possible API change to support partial-byte suffixes.
|
||||
*/
|
||||
protected int doFinal(byte[] out, int outOff, int outLen, byte partialByte, int partialBits)
|
||||
{
|
||||
if (partialBits < 0 || partialBits > 7)
|
||||
{
|
||||
throw new IllegalArgumentException("'partialBits' must be in the range [0,7]");
|
||||
}
|
||||
|
||||
int finalInput = (partialByte & ((1 << partialBits) - 1)) | (0x0F << partialBits);
|
||||
int finalBits = partialBits + 4;
|
||||
|
||||
if (finalBits >= 8)
|
||||
{
|
||||
absorb((byte)finalInput);
|
||||
finalBits -= 8;
|
||||
finalInput >>>= 8;
|
||||
}
|
||||
|
||||
if (finalBits > 0)
|
||||
{
|
||||
absorbBits(finalInput, finalBits);
|
||||
}
|
||||
|
||||
squeeze(out, outOff, ((long)outLen) * 8);
|
||||
|
||||
reset();
|
||||
|
||||
return outLen;
|
||||
}
|
||||
|
||||
protected CryptoServiceProperties cryptoServiceProperties()
|
||||
{
|
||||
return Utils.getDefaultProperties(this, purpose);
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Message digest classes.
|
||||
*/
|
||||
package org.bouncycastle.crypto.digests;
|
@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Base classes for the lightweight API.
|
||||
*/
|
||||
package org.bouncycastle.crypto;
|
@ -0,0 +1,20 @@
|
||||
package org.bouncycastle.crypto.params;
|
||||
|
||||
import org.bouncycastle.crypto.CipherParameters;
|
||||
|
||||
public class AsymmetricKeyParameter
|
||||
implements CipherParameters
|
||||
{
|
||||
boolean privateKey;
|
||||
|
||||
public AsymmetricKeyParameter(
|
||||
boolean privateKey)
|
||||
{
|
||||
this.privateKey = privateKey;
|
||||
}
|
||||
|
||||
public boolean isPrivate()
|
||||
{
|
||||
return privateKey;
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package org.bouncycastle.crypto.params;
|
||||
|
||||
import org.bouncycastle.crypto.CipherParameters;
|
||||
import org.bouncycastle.util.Arrays;
|
||||
|
||||
public class ParametersWithContext
|
||||
implements CipherParameters
|
||||
{
|
||||
private CipherParameters parameters;
|
||||
private byte[] context;
|
||||
|
||||
public ParametersWithContext(
|
||||
CipherParameters parameters,
|
||||
byte[] context)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
throw new NullPointerException("'context' cannot be null");
|
||||
}
|
||||
|
||||
this.parameters = parameters;
|
||||
this.context = Arrays.clone(context);
|
||||
}
|
||||
|
||||
public void copyContextTo(byte[] buf, int off, int len)
|
||||
{
|
||||
if (context.length != len)
|
||||
{
|
||||
throw new IllegalArgumentException("len");
|
||||
}
|
||||
|
||||
System.arraycopy(context, 0, buf, off, len);
|
||||
}
|
||||
|
||||
public byte[] getContext()
|
||||
{
|
||||
return Arrays.clone(context);
|
||||
}
|
||||
|
||||
public int getContextLength()
|
||||
{
|
||||
return context.length;
|
||||
}
|
||||
|
||||
public CipherParameters getParameters()
|
||||
{
|
||||
return parameters;
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package org.bouncycastle.crypto.params;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
|
||||
import org.bouncycastle.crypto.CipherParameters;
|
||||
import org.bouncycastle.crypto.CryptoServicesRegistrar;
|
||||
|
||||
public class ParametersWithRandom
|
||||
implements CipherParameters
|
||||
{
|
||||
private SecureRandom random;
|
||||
private CipherParameters parameters;
|
||||
|
||||
public ParametersWithRandom(
|
||||
CipherParameters parameters,
|
||||
SecureRandom random)
|
||||
{
|
||||
this.random = CryptoServicesRegistrar.getSecureRandom(random);
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
public ParametersWithRandom(
|
||||
CipherParameters parameters)
|
||||
{
|
||||
this(parameters, null);
|
||||
}
|
||||
|
||||
public SecureRandom getRandom()
|
||||
{
|
||||
return random;
|
||||
}
|
||||
|
||||
public CipherParameters getParameters()
|
||||
{
|
||||
return parameters;
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Classes for parameter objects for ciphers and generators.
|
||||
*/
|
||||
package org.bouncycastle.crypto.params;
|
@ -0,0 +1,8 @@
|
||||
package org.bouncycastle.pqc.crypto;
|
||||
|
||||
import org.bouncycastle.crypto.CipherParameters;
|
||||
|
||||
public interface KEMParameters
|
||||
extends CipherParameters
|
||||
{
|
||||
}
|
84
router/java/src/org/bouncycastle/pqc/crypto/mlkem/CBD.java
Normal file
84
router/java/src/org/bouncycastle/pqc/crypto/mlkem/CBD.java
Normal file
@ -0,0 +1,84 @@
|
||||
package org.bouncycastle.pqc.crypto.mlkem;
|
||||
|
||||
final class CBD
|
||||
{
|
||||
|
||||
public static void mlkemCBD(Poly r, byte[] bytes, int eta)
|
||||
{
|
||||
long t, d;
|
||||
int a, b;
|
||||
|
||||
switch (eta)
|
||||
{
|
||||
case 3:
|
||||
for (int i = 0; i < MLKEMEngine.KyberN / 4; i++)
|
||||
{
|
||||
t = convertByteTo24BitUnsignedInt(bytes, 3 * i);
|
||||
d = t & 0x00249249;
|
||||
d = d + ((t >> 1) & 0x00249249);
|
||||
d = d + ((t >> 2) & 0x00249249);
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
a = (short)((d >> (6 * j + 0)) & 0x7);
|
||||
b = (short)((d >> (6 * j + 3)) & 0x7);
|
||||
// System.out.printf("a = %d, b = %d\n", a, b);
|
||||
r.setCoeffIndex(4 * i + j, (short)(a - b));
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Only for Kyber512 where eta = 2
|
||||
for (int i = 0; i < MLKEMEngine.KyberN / 8; i++)
|
||||
{
|
||||
t = convertByteTo32BitUnsignedInt(bytes, 4 * i); // ? Problem
|
||||
d = t & 0x55555555;
|
||||
d = d + ((t >> 1) & 0x55555555);
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
a = (short)((d >> (4 * j + 0)) & 0x3);
|
||||
b = (short)((d >> (4 * j + eta)) & 0x3);
|
||||
r.setCoeffIndex(8 * i + j, (short)(a - b));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an Array of Bytes to a 32-bit Unsigned Integer
|
||||
* Returns a 32-bit unsigned integer as a long
|
||||
*
|
||||
* @param x
|
||||
* @return
|
||||
*/
|
||||
private static long convertByteTo32BitUnsignedInt(byte[] x, int offset)
|
||||
{
|
||||
// Convert first byte to an unsigned integer
|
||||
// byte x & 0xFF allows us to grab the last 8 bits
|
||||
long r = (long)(x[offset] & 0xFF);
|
||||
|
||||
// Perform the same operation then left bit shift to store the next 8 bits without
|
||||
// altering the previous bits
|
||||
r = r | (long)((long)(x[offset + 1] & 0xFF) << 8);
|
||||
r = r | (long)((long)(x[offset + 2] & 0xFF) << 16);
|
||||
r = r | (long)((long)(x[offset + 3] & 0xFF) << 24);
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an Array of Bytes to a 24-bit Unsigned Integer
|
||||
* Returns a 24-bit unsigned integer as a long from byte x
|
||||
*
|
||||
* @param x
|
||||
* @return
|
||||
*/
|
||||
private static long convertByteTo24BitUnsignedInt(byte[] x, int offset)
|
||||
{
|
||||
// Refer to convertByteTo32-BitUnsignedInt for explanation
|
||||
long r = (long)(x[offset] & 0xFF);
|
||||
r = r | (long)((long)(x[offset + 1] & 0xFF) << 8);
|
||||
r = r | (long)((long)(x[offset + 2] & 0xFF) << 16);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,326 @@
|
||||
package org.bouncycastle.pqc.crypto.mlkem;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
|
||||
import org.bouncycastle.util.Arrays;
|
||||
|
||||
class MLKEMEngine
|
||||
{
|
||||
private SecureRandom random;
|
||||
private MLKEMIndCpa indCpa;
|
||||
|
||||
// constant parameters
|
||||
public final static int KyberN = 256;
|
||||
public final static int KyberQ = 3329;
|
||||
public final static int KyberQinv = 62209;
|
||||
|
||||
public final static int KyberSymBytes = 32; // Number of bytes for Hashes and Seeds
|
||||
private final static int KyberSharedSecretBytes = 32; // Number of Bytes for Shared Secret
|
||||
|
||||
public final static int KyberPolyBytes = 384;
|
||||
|
||||
private final static int KyberEta2 = 2;
|
||||
|
||||
private final static int KyberIndCpaMsgBytes = KyberSymBytes;
|
||||
|
||||
|
||||
// parameters for Kyber{k}
|
||||
private final int KyberK;
|
||||
private final int KyberPolyVecBytes;
|
||||
private final int KyberPolyCompressedBytes;
|
||||
private final int KyberPolyVecCompressedBytes;
|
||||
private final int KyberEta1;
|
||||
private final int KyberIndCpaPublicKeyBytes;
|
||||
private final int KyberIndCpaSecretKeyBytes;
|
||||
private final int KyberIndCpaBytes;
|
||||
private final int KyberPublicKeyBytes;
|
||||
private final int KyberSecretKeyBytes;
|
||||
private final int KyberCipherTextBytes;
|
||||
|
||||
// Crypto
|
||||
private final int CryptoBytes;
|
||||
private final int CryptoSecretKeyBytes;
|
||||
private final int CryptoPublicKeyBytes;
|
||||
private final int CryptoCipherTextBytes;
|
||||
|
||||
private final int sessionKeyLength;
|
||||
private final Symmetric symmetric;
|
||||
|
||||
public Symmetric getSymmetric()
|
||||
{
|
||||
return symmetric;
|
||||
}
|
||||
public static int getKyberEta2()
|
||||
{
|
||||
return KyberEta2;
|
||||
}
|
||||
|
||||
public static int getKyberIndCpaMsgBytes()
|
||||
{
|
||||
return KyberIndCpaMsgBytes;
|
||||
}
|
||||
|
||||
public int getCryptoCipherTextBytes()
|
||||
{
|
||||
return CryptoCipherTextBytes;
|
||||
}
|
||||
|
||||
public int getCryptoPublicKeyBytes()
|
||||
{
|
||||
return CryptoPublicKeyBytes;
|
||||
}
|
||||
|
||||
public int getCryptoSecretKeyBytes()
|
||||
{
|
||||
return CryptoSecretKeyBytes;
|
||||
}
|
||||
|
||||
public int getCryptoBytes()
|
||||
{
|
||||
return CryptoBytes;
|
||||
}
|
||||
|
||||
public int getKyberCipherTextBytes()
|
||||
{
|
||||
return KyberCipherTextBytes;
|
||||
}
|
||||
|
||||
public int getKyberSecretKeyBytes()
|
||||
{
|
||||
return KyberSecretKeyBytes;
|
||||
}
|
||||
|
||||
public int getKyberIndCpaPublicKeyBytes()
|
||||
{
|
||||
return KyberIndCpaPublicKeyBytes;
|
||||
}
|
||||
|
||||
|
||||
public int getKyberIndCpaSecretKeyBytes()
|
||||
{
|
||||
return KyberIndCpaSecretKeyBytes;
|
||||
}
|
||||
|
||||
public int getKyberIndCpaBytes()
|
||||
{
|
||||
return KyberIndCpaBytes;
|
||||
}
|
||||
|
||||
public int getKyberPublicKeyBytes()
|
||||
{
|
||||
return KyberPublicKeyBytes;
|
||||
}
|
||||
|
||||
public int getKyberPolyCompressedBytes()
|
||||
{
|
||||
return KyberPolyCompressedBytes;
|
||||
}
|
||||
|
||||
public int getKyberK()
|
||||
{
|
||||
return KyberK;
|
||||
}
|
||||
|
||||
public int getKyberPolyVecBytes()
|
||||
{
|
||||
return KyberPolyVecBytes;
|
||||
}
|
||||
|
||||
public int getKyberPolyVecCompressedBytes()
|
||||
{
|
||||
return KyberPolyVecCompressedBytes;
|
||||
}
|
||||
|
||||
public int getKyberEta1()
|
||||
{
|
||||
return KyberEta1;
|
||||
}
|
||||
|
||||
public MLKEMEngine(int k)
|
||||
{
|
||||
this.KyberK = k;
|
||||
switch (k)
|
||||
{
|
||||
case 2:
|
||||
KyberEta1 = 3;
|
||||
KyberPolyCompressedBytes = 128;
|
||||
KyberPolyVecCompressedBytes = k * 320;
|
||||
sessionKeyLength = 32;
|
||||
break;
|
||||
case 3:
|
||||
KyberEta1 = 2;
|
||||
KyberPolyCompressedBytes = 128;
|
||||
KyberPolyVecCompressedBytes = k * 320;
|
||||
sessionKeyLength = 32;
|
||||
break;
|
||||
case 4:
|
||||
KyberEta1 = 2;
|
||||
KyberPolyCompressedBytes = 160;
|
||||
KyberPolyVecCompressedBytes = k * 352;
|
||||
sessionKeyLength = 32;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("K: " + k + " is not supported for Crystals Kyber");
|
||||
}
|
||||
|
||||
this.KyberPolyVecBytes = k * KyberPolyBytes;
|
||||
this.KyberIndCpaPublicKeyBytes = KyberPolyVecBytes + KyberSymBytes;
|
||||
this.KyberIndCpaSecretKeyBytes = KyberPolyVecBytes;
|
||||
this.KyberIndCpaBytes = KyberPolyVecCompressedBytes + KyberPolyCompressedBytes;
|
||||
this.KyberPublicKeyBytes = KyberIndCpaPublicKeyBytes;
|
||||
this.KyberSecretKeyBytes = KyberIndCpaSecretKeyBytes + KyberIndCpaPublicKeyBytes + 2 * KyberSymBytes;
|
||||
this.KyberCipherTextBytes = KyberIndCpaBytes;
|
||||
|
||||
// Define Crypto Params
|
||||
this.CryptoBytes = KyberSharedSecretBytes;
|
||||
this.CryptoSecretKeyBytes = KyberSecretKeyBytes;
|
||||
this.CryptoPublicKeyBytes = KyberPublicKeyBytes;
|
||||
this.CryptoCipherTextBytes = KyberCipherTextBytes;
|
||||
|
||||
this.symmetric = new Symmetric.ShakeSymmetric();
|
||||
|
||||
this.indCpa = new MLKEMIndCpa(this);
|
||||
}
|
||||
|
||||
public void init(SecureRandom random)
|
||||
{
|
||||
this.random = random;
|
||||
}
|
||||
|
||||
public byte[][] generateKemKeyPair()
|
||||
{
|
||||
byte[] d = new byte[KyberSymBytes];
|
||||
byte[] z = new byte[KyberSymBytes];
|
||||
random.nextBytes(d);
|
||||
random.nextBytes(z);
|
||||
|
||||
return generateKemKeyPairInternal(d, z);
|
||||
}
|
||||
|
||||
//Internal functions are deterministic. No randomness is sampled inside them
|
||||
public byte[][] generateKemKeyPairInternal(byte[] d, byte[] z)
|
||||
{
|
||||
byte[][] indCpaKeyPair = indCpa.generateKeyPair(d);
|
||||
|
||||
byte[] s = new byte[KyberIndCpaSecretKeyBytes];
|
||||
|
||||
System.arraycopy(indCpaKeyPair[1], 0, s, 0, KyberIndCpaSecretKeyBytes);
|
||||
|
||||
byte[] hashedPublicKey = new byte[32];
|
||||
|
||||
symmetric.hash_h(hashedPublicKey, indCpaKeyPair[0], 0);
|
||||
|
||||
byte[] outputPublicKey = new byte[KyberIndCpaPublicKeyBytes];
|
||||
System.arraycopy(indCpaKeyPair[0], 0, outputPublicKey, 0, KyberIndCpaPublicKeyBytes);
|
||||
return new byte[][]
|
||||
{
|
||||
Arrays.copyOfRange(outputPublicKey, 0, outputPublicKey.length - 32),
|
||||
Arrays.copyOfRange(outputPublicKey, outputPublicKey.length - 32, outputPublicKey.length),
|
||||
s,
|
||||
hashedPublicKey,
|
||||
z,
|
||||
Arrays.concatenate(d, z)
|
||||
};
|
||||
}
|
||||
|
||||
public byte[][] kemEncryptInternal(byte[] publicKeyInput, byte[] randBytes)
|
||||
{
|
||||
byte[] outputCipherText;
|
||||
|
||||
byte[] buf = new byte[2 * KyberSymBytes];
|
||||
byte[] kr = new byte[2 * KyberSymBytes];
|
||||
|
||||
System.arraycopy(randBytes, 0, buf, 0, KyberSymBytes);
|
||||
|
||||
// SHA3-256 Public Key
|
||||
symmetric.hash_h(buf, publicKeyInput, KyberSymBytes);
|
||||
|
||||
// SHA3-512( SHA3-256(RandBytes) || SHA3-256(PublicKey) )
|
||||
symmetric.hash_g(kr, buf);
|
||||
|
||||
// IndCpa Encryption
|
||||
outputCipherText = indCpa.encrypt(publicKeyInput, Arrays.copyOfRange(buf, 0, KyberSymBytes), Arrays.copyOfRange(kr, 32, kr.length));
|
||||
|
||||
byte[] outputSharedSecret = new byte[sessionKeyLength];
|
||||
|
||||
System.arraycopy(kr, 0, outputSharedSecret, 0, outputSharedSecret.length);
|
||||
|
||||
byte[][] outBuf = new byte[2][];
|
||||
outBuf[0] = outputSharedSecret;
|
||||
outBuf[1] = outputCipherText;
|
||||
return outBuf;
|
||||
}
|
||||
|
||||
public byte[] kemDecryptInternal(byte[] secretKey, byte[] cipherText)
|
||||
{
|
||||
byte[] buf = new byte[2 * KyberSymBytes],
|
||||
kr = new byte[2 * KyberSymBytes];
|
||||
|
||||
byte[] publicKey = Arrays.copyOfRange(secretKey, KyberIndCpaSecretKeyBytes, secretKey.length);
|
||||
|
||||
System.arraycopy(indCpa.decrypt(secretKey, cipherText), 0, buf, 0, KyberSymBytes);
|
||||
|
||||
System.arraycopy(secretKey, KyberSecretKeyBytes - 2 * KyberSymBytes, buf, KyberSymBytes, KyberSymBytes);
|
||||
|
||||
symmetric.hash_g(kr, buf);
|
||||
|
||||
byte[] implicit_rejection = new byte[KyberSymBytes + KyberCipherTextBytes];
|
||||
|
||||
System.arraycopy(secretKey, KyberSecretKeyBytes - KyberSymBytes, implicit_rejection, 0, KyberSymBytes);
|
||||
|
||||
System.arraycopy(cipherText, 0, implicit_rejection, KyberSymBytes, KyberCipherTextBytes);
|
||||
|
||||
symmetric.kdf(implicit_rejection, implicit_rejection ); // J(z||c)
|
||||
|
||||
byte[] cmp = indCpa.encrypt(publicKey, Arrays.copyOfRange(buf, 0, KyberSymBytes), Arrays.copyOfRange(kr, KyberSymBytes, kr.length));
|
||||
|
||||
boolean fail = !(Arrays.constantTimeAreEqual(cipherText, cmp));
|
||||
|
||||
cmov(kr, implicit_rejection, KyberSymBytes, fail);
|
||||
|
||||
return Arrays.copyOfRange(kr, 0, sessionKeyLength);
|
||||
}
|
||||
|
||||
public byte[][] kemEncrypt(byte[] publicKeyInput, byte[] randBytes)
|
||||
{
|
||||
//TODO: do input validation elsewhere?
|
||||
// Input validation (6.2 ML-KEM Encaps)
|
||||
// Type Check
|
||||
if (publicKeyInput.length != KyberIndCpaPublicKeyBytes)
|
||||
{
|
||||
throw new IllegalArgumentException("Input validation Error: Type check failed for ml-kem encapsulation");
|
||||
}
|
||||
// Modulus Check
|
||||
PolyVec polyVec = new PolyVec(this);
|
||||
byte[] seed = indCpa.unpackPublicKey(polyVec, publicKeyInput);
|
||||
byte[] ek = indCpa.packPublicKey(polyVec, seed);
|
||||
if (!Arrays.areEqual(ek, publicKeyInput))
|
||||
{
|
||||
throw new IllegalArgumentException("Input validation: Modulus check failed for ml-kem encapsulation");
|
||||
}
|
||||
|
||||
return kemEncryptInternal(publicKeyInput, randBytes);
|
||||
}
|
||||
public byte[] kemDecrypt(byte[] secretKey, byte[] cipherText)
|
||||
{
|
||||
//TODO: do input validation
|
||||
return kemDecryptInternal(secretKey, cipherText);
|
||||
}
|
||||
|
||||
private void cmov(byte[] r, byte[] x, int xlen, boolean b)
|
||||
{
|
||||
if (b)
|
||||
{
|
||||
System.arraycopy(x, 0, r, 0, xlen);
|
||||
}
|
||||
else
|
||||
{
|
||||
System.arraycopy(r, 0, r, 0, xlen);
|
||||
}
|
||||
}
|
||||
|
||||
public void getRandomBytes(byte[] buf)
|
||||
{
|
||||
this.random.nextBytes(buf);
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package org.bouncycastle.pqc.crypto.mlkem;
|
||||
|
||||
import org.bouncycastle.crypto.EncapsulatedSecretExtractor;
|
||||
|
||||
public class MLKEMExtractor
|
||||
implements EncapsulatedSecretExtractor
|
||||
{
|
||||
private final MLKEMPrivateKeyParameters privateKey;
|
||||
private final MLKEMEngine engine;
|
||||
|
||||
public MLKEMExtractor(MLKEMPrivateKeyParameters privateKey)
|
||||
{
|
||||
if (privateKey == null)
|
||||
{
|
||||
throw new NullPointerException("'privateKey' cannot be null");
|
||||
}
|
||||
|
||||
this.privateKey = privateKey;
|
||||
this.engine = privateKey.getParameters().getEngine();
|
||||
}
|
||||
|
||||
public byte[] extractSecret(byte[] encapsulation)
|
||||
{
|
||||
return engine.kemDecrypt(privateKey.getEncoded(), encapsulation);
|
||||
}
|
||||
|
||||
public int getEncapsulationLength()
|
||||
{
|
||||
return engine.getCryptoCipherTextBytes();
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package org.bouncycastle.pqc.crypto.mlkem;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
|
||||
import org.bouncycastle.crypto.EncapsulatedSecretGenerator;
|
||||
import org.bouncycastle.crypto.SecretWithEncapsulation;
|
||||
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
|
||||
import org.bouncycastle.pqc.crypto.util.SecretWithEncapsulationImpl;
|
||||
|
||||
public class MLKEMGenerator
|
||||
implements EncapsulatedSecretGenerator
|
||||
{
|
||||
// the source of randomness
|
||||
private final SecureRandom sr;
|
||||
|
||||
public MLKEMGenerator(SecureRandom random)
|
||||
{
|
||||
this.sr = random;
|
||||
}
|
||||
|
||||
public SecretWithEncapsulation generateEncapsulated(AsymmetricKeyParameter recipientKey)
|
||||
{
|
||||
MLKEMPublicKeyParameters key = (MLKEMPublicKeyParameters)recipientKey;
|
||||
MLKEMEngine engine = key.getParameters().getEngine();
|
||||
engine.init(sr);
|
||||
|
||||
byte[] randBytes = new byte[32];
|
||||
engine.getRandomBytes(randBytes);
|
||||
|
||||
byte[][] kemEncrypt = engine.kemEncrypt(key.getEncoded(), randBytes);
|
||||
return new SecretWithEncapsulationImpl(kemEncrypt[0], kemEncrypt[1]);
|
||||
}
|
||||
public SecretWithEncapsulation internalGenerateEncapsulated(AsymmetricKeyParameter recipientKey, byte[] randBytes)
|
||||
{
|
||||
MLKEMPublicKeyParameters key = (MLKEMPublicKeyParameters)recipientKey;
|
||||
MLKEMEngine engine = key.getParameters().getEngine();
|
||||
engine.init(sr);
|
||||
|
||||
byte[][] kemEncrypt = engine.kemEncryptInternal(key.getEncoded(), randBytes);
|
||||
return new SecretWithEncapsulationImpl(kemEncrypt[0], kemEncrypt[1]);
|
||||
}
|
||||
}
|
@ -0,0 +1,444 @@
|
||||
package org.bouncycastle.pqc.crypto.mlkem;
|
||||
|
||||
import org.bouncycastle.util.Arrays;
|
||||
|
||||
class MLKEMIndCpa
|
||||
{
|
||||
private MLKEMEngine engine;
|
||||
private int kyberK;
|
||||
private int indCpaPublicKeyBytes;
|
||||
private int polyVecBytes;
|
||||
private int indCpaBytes;
|
||||
private int polyVecCompressedBytes;
|
||||
private int polyCompressedBytes;
|
||||
|
||||
private Symmetric symmetric;
|
||||
|
||||
public MLKEMIndCpa(MLKEMEngine engine)
|
||||
{
|
||||
this.engine = engine;
|
||||
this.kyberK = engine.getKyberK();
|
||||
this.indCpaPublicKeyBytes = engine.getKyberPublicKeyBytes();
|
||||
this.polyVecBytes = engine.getKyberPolyVecBytes();
|
||||
this.indCpaBytes = engine.getKyberIndCpaBytes();
|
||||
this.polyVecCompressedBytes = engine.getKyberPolyVecCompressedBytes();
|
||||
this.polyCompressedBytes = engine.getKyberPolyCompressedBytes();
|
||||
this.symmetric = engine.getSymmetric();
|
||||
|
||||
KyberGenerateMatrixNBlocks =
|
||||
(
|
||||
(
|
||||
12 * MLKEMEngine.KyberN
|
||||
/ 8 * (1 << 12)
|
||||
/ MLKEMEngine.KyberQ + symmetric.xofBlockBytes
|
||||
)
|
||||
/ symmetric.xofBlockBytes
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates IndCpa Key Pair
|
||||
*
|
||||
* @return KeyPair where each key is represented as bytes
|
||||
*/
|
||||
byte[][] generateKeyPair(byte[] d)
|
||||
{
|
||||
PolyVec secretKey = new PolyVec(engine),
|
||||
publicKey = new PolyVec(engine),
|
||||
e = new PolyVec(engine);
|
||||
|
||||
// (p, sigma) <- G(d || k)
|
||||
|
||||
byte[] buf = new byte[64];
|
||||
symmetric.hash_g(buf, Arrays.append(d, (byte)kyberK));
|
||||
|
||||
byte[] publicSeed = new byte[32]; // p in docs
|
||||
byte[] noiseSeed = new byte[32]; // sigma in docs
|
||||
System.arraycopy(buf, 0, publicSeed, 0, 32);
|
||||
System.arraycopy(buf, 32, noiseSeed, 0, 32);
|
||||
|
||||
byte count = (byte)0;
|
||||
|
||||
// Helper.printByteArray(buf);
|
||||
|
||||
|
||||
PolyVec[] aMatrix = new PolyVec[kyberK];
|
||||
|
||||
int i;
|
||||
for (i = 0; i < kyberK; i++)
|
||||
{
|
||||
aMatrix[i] = new PolyVec(engine);
|
||||
}
|
||||
|
||||
generateMatrix(aMatrix, publicSeed, false);
|
||||
|
||||
// System.out.println("aMatrix = ");
|
||||
// for(i = 0; i < kyberK; i++) {
|
||||
// System.out.print("[");
|
||||
// for (int j = 0; j < kyberK; j++) {
|
||||
// System.out.print("[");
|
||||
// for (int k = 0; k < KyberEngine.KyberN; k++) {
|
||||
// System.out.printf("%d ,", aMatrix[i].getVectorIndex(j).getCoeffIndex(k));
|
||||
// }
|
||||
// System.out.print("], \n");
|
||||
// }
|
||||
// System.out.print("]\n");
|
||||
// }
|
||||
|
||||
for (i = 0; i < kyberK; i++)
|
||||
{
|
||||
secretKey.getVectorIndex(i).getEta1Noise(noiseSeed, count);
|
||||
|
||||
// System.out.print("SecretKeyPolyVec["+i+"] = [");
|
||||
// for (int j =0; j < KyberEngine.KyberN; j++) {
|
||||
// System.out.print(secretKey.getVectorIndex(i).getCoeffIndex(j) + ", ");
|
||||
// }
|
||||
// System.out.println("]");
|
||||
count = (byte)(count + (byte)1);
|
||||
}
|
||||
|
||||
for (i = 0; i < kyberK; i++)
|
||||
{
|
||||
e.getVectorIndex(i).getEta1Noise(noiseSeed, count);
|
||||
count = (byte)(count + (byte)1);
|
||||
}
|
||||
|
||||
secretKey.polyVecNtt();
|
||||
|
||||
// System.out.print("SecretKeyPolyVec = [");
|
||||
// for (i = 0; i < kyberK; i++) {
|
||||
// System.out.print("[");
|
||||
// for (int j =0; j < KyberEngine.KyberN; j++) {
|
||||
// System.out.print(secretKey.getVectorIndex(i).getCoeffIndex(j) + ", ");
|
||||
// }
|
||||
// System.out.println("],");
|
||||
// }
|
||||
// System.out.println("]");
|
||||
|
||||
|
||||
e.polyVecNtt();
|
||||
|
||||
for (i = 0; i < kyberK; i++)
|
||||
{
|
||||
PolyVec.pointwiseAccountMontgomery(publicKey.getVectorIndex(i), aMatrix[i], secretKey, engine);
|
||||
publicKey.getVectorIndex(i).convertToMont();
|
||||
}
|
||||
|
||||
// System.out.print("PublicKey PolyVec = [");
|
||||
// Helper.printPolyVec(publicKey, kyberK);
|
||||
|
||||
publicKey.addPoly(e);
|
||||
publicKey.reducePoly();
|
||||
|
||||
return new byte[][]{packPublicKey(publicKey, publicSeed), packSecretKey(secretKey)};
|
||||
}
|
||||
|
||||
public byte[] encrypt(byte[] publicKeyInput, byte[] msg, byte[] coins)
|
||||
{
|
||||
int i;
|
||||
byte[] seed;
|
||||
byte nonce = (byte)0;
|
||||
PolyVec sp = new PolyVec(engine),
|
||||
publicKeyPolyVec = new PolyVec(engine),
|
||||
errorPolyVector = new PolyVec(engine),
|
||||
bp = new PolyVec(engine);
|
||||
PolyVec[] aMatrixTranspose = new PolyVec[engine.getKyberK()];
|
||||
Poly errorPoly = new Poly(engine),
|
||||
v = new Poly(engine),
|
||||
k = new Poly(engine);
|
||||
|
||||
|
||||
// System.out.print("publickeyinput = ");
|
||||
// Helper.printByteArray(publicKeyInput);
|
||||
// System.out.println();
|
||||
|
||||
seed = unpackPublicKey(publicKeyPolyVec, publicKeyInput);
|
||||
|
||||
// System.out.print("publickeyPolyVec = [");
|
||||
// for (i = 0; i < kyberK; i++) {
|
||||
// Helper.printShortArray(publicKeyPolyVec.getVectorIndex(i).getCoeffs());
|
||||
// System.out.print("], \n");
|
||||
// }
|
||||
// System.out.println("]");
|
||||
|
||||
// System.out.print("seed = ");
|
||||
// Helper.printByteArray(seed);
|
||||
// System.out.println();
|
||||
|
||||
k.fromMsg(msg);
|
||||
|
||||
for (i = 0; i < kyberK; i++)
|
||||
{
|
||||
aMatrixTranspose[i] = new PolyVec(engine);
|
||||
}
|
||||
|
||||
generateMatrix(aMatrixTranspose, seed, true);
|
||||
|
||||
// System.out.print("matrix transposed = ");
|
||||
// for (i = 0; i < kyberK; i++) {
|
||||
// System.out.print("[");
|
||||
// for(int j = 0; j < kyberK; j++) {
|
||||
// System.out.print("[");
|
||||
// for (int l = 0; l < 256; l++) {
|
||||
// System.out.printf("%d ,", aMatrixTranspose[i].getVectorIndex(j).getCoeffIndex(l));
|
||||
// }
|
||||
// System.out.print("] ,\n");
|
||||
// }
|
||||
// System.out.println("] ,");
|
||||
// }
|
||||
|
||||
|
||||
for (i = 0; i < kyberK; i++)
|
||||
{
|
||||
sp.getVectorIndex(i).getEta1Noise(coins, nonce);
|
||||
nonce = (byte)(nonce + (byte)1);
|
||||
}
|
||||
|
||||
|
||||
for (i = 0; i < kyberK; i++)
|
||||
{
|
||||
errorPolyVector.getVectorIndex(i).getEta2Noise(coins, nonce);
|
||||
nonce = (byte)(nonce + (byte)1);
|
||||
}
|
||||
errorPoly.getEta2Noise(coins, nonce);
|
||||
|
||||
sp.polyVecNtt();
|
||||
|
||||
// System.out.print("sp = [");
|
||||
// for (i = 0; i < kyberK; i++) {
|
||||
// Helper.printShortArray(sp.getVectorIndex(i).getCoeffs());
|
||||
// System.out.print("], \n");
|
||||
// }
|
||||
// System.out.println("]");
|
||||
|
||||
|
||||
// System.out.print("sp = [");
|
||||
// for (i = 0; i < kyberK; i++) {
|
||||
// Helper.printShortArray(sp.getVectorIndex(i).getCoeffs());
|
||||
// System.out.print("], \n");
|
||||
// }
|
||||
// System.out.println("]");
|
||||
|
||||
for (i = 0; i < kyberK; i++)
|
||||
{
|
||||
|
||||
PolyVec.pointwiseAccountMontgomery(bp.getVectorIndex(i), aMatrixTranspose[i], sp, engine);
|
||||
}
|
||||
// System.out.print("bp = [");
|
||||
// for (i = 0; i < kyberK; i++) {
|
||||
// Helper.printShortArray(bp.getVectorIndex(i).getCoeffs());
|
||||
// System.out.print("], \n");
|
||||
// }
|
||||
// System.out.println("]");
|
||||
|
||||
PolyVec.pointwiseAccountMontgomery(v, publicKeyPolyVec, sp, engine);
|
||||
|
||||
bp.polyVecInverseNttToMont();
|
||||
|
||||
v.polyInverseNttToMont();
|
||||
|
||||
bp.addPoly(errorPolyVector);
|
||||
|
||||
|
||||
v.addCoeffs(errorPoly);
|
||||
v.addCoeffs(k);
|
||||
|
||||
bp.reducePoly();
|
||||
v.reduce();
|
||||
|
||||
// System.out.print("bp = [");
|
||||
// for (i = 0; i < kyberK; i++) {
|
||||
// Helper.printShortArray(bp.getVectorIndex(i).getCoeffs());
|
||||
// System.out.print("], \n");
|
||||
// }
|
||||
// System.out.println("]");
|
||||
|
||||
|
||||
// System.out.print("v = ");
|
||||
// Helper.printShortArray(v.getCoeffs());
|
||||
// System.out.println();
|
||||
|
||||
|
||||
byte[] outputCipherText = packCipherText(bp, v);
|
||||
|
||||
return outputCipherText;
|
||||
}
|
||||
|
||||
private byte[] packCipherText(PolyVec b, Poly v)
|
||||
{
|
||||
byte[] outBuf = new byte[indCpaBytes];
|
||||
System.arraycopy(b.compressPolyVec(), 0, outBuf, 0, polyVecCompressedBytes);
|
||||
System.arraycopy(v.compressPoly(), 0, outBuf, polyVecCompressedBytes, polyCompressedBytes);
|
||||
// System.out.print("outBuf = [");
|
||||
// Helper.printByteArray(outBuf);
|
||||
return outBuf;
|
||||
}
|
||||
|
||||
private void unpackCipherText(PolyVec b, Poly v, byte[] cipherText)
|
||||
{
|
||||
byte[] compressedPolyVecCipherText = Arrays.copyOfRange(cipherText, 0, engine.getKyberPolyVecCompressedBytes());
|
||||
b.decompressPolyVec(compressedPolyVecCipherText);
|
||||
|
||||
byte[] compressedPolyCipherText = Arrays.copyOfRange(cipherText, engine.getKyberPolyVecCompressedBytes(), cipherText.length);
|
||||
v.decompressPoly(compressedPolyCipherText);
|
||||
}
|
||||
|
||||
public byte[] packPublicKey(PolyVec publicKeyPolyVec, byte[] seed)
|
||||
{
|
||||
byte[] buf = new byte[indCpaPublicKeyBytes];
|
||||
System.arraycopy(publicKeyPolyVec.toBytes(), 0, buf, 0, polyVecBytes);
|
||||
System.arraycopy(seed, 0, buf, polyVecBytes, MLKEMEngine.KyberSymBytes);
|
||||
return buf;
|
||||
}
|
||||
|
||||
public byte[] unpackPublicKey(PolyVec publicKeyPolyVec, byte[] publicKey)
|
||||
{
|
||||
byte[] outputSeed = new byte[MLKEMEngine.KyberSymBytes];
|
||||
publicKeyPolyVec.fromBytes(publicKey);
|
||||
System.arraycopy(publicKey, polyVecBytes, outputSeed, 0, MLKEMEngine.KyberSymBytes);
|
||||
return outputSeed;
|
||||
}
|
||||
|
||||
public byte[] packSecretKey(PolyVec secretKeyPolyVec)
|
||||
{
|
||||
return secretKeyPolyVec.toBytes();
|
||||
}
|
||||
|
||||
public void unpackSecretKey(PolyVec secretKeyPolyVec, byte[] secretKey)
|
||||
{
|
||||
secretKeyPolyVec.fromBytes(secretKey);
|
||||
}
|
||||
|
||||
public final int KyberGenerateMatrixNBlocks;
|
||||
|
||||
public void generateMatrix(PolyVec[] aMatrix, byte[] seed, boolean transposed)
|
||||
{
|
||||
int i, j, k, ctr, off;
|
||||
byte[] buf = new byte[KyberGenerateMatrixNBlocks * symmetric.xofBlockBytes + 2];
|
||||
for (i = 0; i < kyberK; i++)
|
||||
{
|
||||
for (j = 0; j < kyberK; j++)
|
||||
{
|
||||
if (transposed)
|
||||
{
|
||||
symmetric.xofAbsorb(seed, (byte) i, (byte) j);
|
||||
}
|
||||
else
|
||||
{
|
||||
symmetric.xofAbsorb(seed, (byte) j, (byte) i);
|
||||
}
|
||||
symmetric.xofSqueezeBlocks(buf, 0, symmetric.xofBlockBytes * KyberGenerateMatrixNBlocks);
|
||||
|
||||
int buflen = KyberGenerateMatrixNBlocks * symmetric.xofBlockBytes;
|
||||
ctr = rejectionSampling(aMatrix[i].getVectorIndex(j), 0, MLKEMEngine.KyberN, buf, buflen);
|
||||
|
||||
while (ctr < MLKEMEngine.KyberN)
|
||||
{
|
||||
off = buflen % 3;
|
||||
for (k = 0; k < off; k++)
|
||||
{
|
||||
buf[k] = buf[buflen - off + k];
|
||||
}
|
||||
symmetric.xofSqueezeBlocks(buf, off, symmetric.xofBlockBytes * 2);
|
||||
buflen = off + symmetric.xofBlockBytes;
|
||||
// Error in code Section Unsure
|
||||
ctr += rejectionSampling(aMatrix[i].getVectorIndex(j), ctr, MLKEMEngine.KyberN - ctr, buf, buflen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static int rejectionSampling(Poly outputBuffer, int coeffOff, int len, byte[] inpBuf, int inpBufLen)
|
||||
{
|
||||
int ctr, pos;
|
||||
short val0, val1;
|
||||
ctr = pos = 0;
|
||||
while (ctr < len && pos + 3 <= inpBufLen)
|
||||
{
|
||||
val0 = (short)(((((short)(inpBuf[pos] & 0xFF)) >> 0) | (((short)(inpBuf[pos + 1] & 0xFF)) << 8)) & 0xFFF);
|
||||
val1 = (short)(((((short)(inpBuf[pos + 1] & 0xFF)) >> 4) | (((short)(inpBuf[pos + 2] & 0xFF)) << 4)) & 0xFFF);
|
||||
pos = pos + 3;
|
||||
if (val0 < (short)MLKEMEngine.KyberQ)
|
||||
{
|
||||
outputBuffer.setCoeffIndex(coeffOff + ctr, (short)val0);
|
||||
ctr++;
|
||||
}
|
||||
if (ctr < len && val1 < (short)MLKEMEngine.KyberQ)
|
||||
{
|
||||
outputBuffer.setCoeffIndex(coeffOff + ctr, (short)val1);
|
||||
ctr++;
|
||||
}
|
||||
}
|
||||
return ctr;
|
||||
|
||||
}
|
||||
|
||||
public byte[] decrypt(byte[] secretKey, byte[] cipherText)
|
||||
{
|
||||
byte[] outputMessage = new byte[MLKEMEngine.getKyberIndCpaMsgBytes()];
|
||||
|
||||
PolyVec bp = new PolyVec(engine), secretKeyPolyVec = new PolyVec(engine);
|
||||
Poly v = new Poly(engine), mp = new Poly(engine);
|
||||
|
||||
unpackCipherText(bp, v, cipherText);
|
||||
|
||||
// System.out.print("bp = [");
|
||||
// for (i = 0; i < kyberK; i++) {
|
||||
// Helper.printShortArray(bp.getVectorIndex(i).getCoeffs());
|
||||
// System.out.print("], \n");
|
||||
// }
|
||||
// System.out.println("]");
|
||||
|
||||
|
||||
// System.out.print("v = ");
|
||||
// Helper.printShortArray(v.getCoeffs());
|
||||
// System.out.println();
|
||||
|
||||
unpackSecretKey(secretKeyPolyVec, secretKey);
|
||||
|
||||
// System.out.print("decrypt secretkey = ");;
|
||||
// Helper.printByteArray(secretKey);
|
||||
|
||||
// System.out.print("SecretKeyPolyVec = [");
|
||||
// for (i = 0; i < kyberK; i++) {
|
||||
// System.out.print("[");
|
||||
// for (int j =0; j < KyberEngine.KyberN; j++) {
|
||||
// System.out.print(secretKeyPolyVec.getVectorIndex(i).getCoeffIndex(j) + ", ");
|
||||
// }
|
||||
// System.out.println("],");
|
||||
// }
|
||||
// System.out.println("]");
|
||||
|
||||
// System.out.print("bp before ntt = [");
|
||||
// for (i = 0; i < kyberK; i++) {
|
||||
// Helper.printShortArray(bp.getVectorIndex(i).getCoeffs());
|
||||
// System.out.print("], \n");
|
||||
// }
|
||||
// System.out.println("]");
|
||||
|
||||
bp.polyVecNtt();
|
||||
|
||||
// System.out.print("bp after ntt = [");
|
||||
// for (i = 0; i < kyberK; i++) {
|
||||
// Helper.printShortArray(bp.getVectorIndex(i).getCoeffs());
|
||||
// System.out.print("], \n");
|
||||
// }
|
||||
// System.out.println("]");
|
||||
|
||||
PolyVec.pointwiseAccountMontgomery(mp, secretKeyPolyVec, bp, engine);
|
||||
|
||||
|
||||
mp.polyInverseNttToMont();
|
||||
|
||||
mp.polySubtract(v);
|
||||
|
||||
mp.reduce();
|
||||
|
||||
outputMessage = mp.toMsg();
|
||||
|
||||
return outputMessage;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package org.bouncycastle.pqc.crypto.mlkem;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
|
||||
import org.bouncycastle.crypto.KeyGenerationParameters;
|
||||
|
||||
public class MLKEMKeyGenerationParameters
|
||||
extends KeyGenerationParameters
|
||||
{
|
||||
private final MLKEMParameters params;
|
||||
|
||||
public MLKEMKeyGenerationParameters(
|
||||
SecureRandom random,
|
||||
MLKEMParameters mlkemParameters)
|
||||
{
|
||||
super(random, 256);
|
||||
this.params = mlkemParameters;
|
||||
}
|
||||
|
||||
public MLKEMParameters getParameters()
|
||||
{
|
||||
return params;
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package org.bouncycastle.pqc.crypto.mlkem;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
|
||||
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
|
||||
import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
|
||||
import org.bouncycastle.crypto.KeyGenerationParameters;
|
||||
|
||||
public class MLKEMKeyPairGenerator
|
||||
implements AsymmetricCipherKeyPairGenerator
|
||||
{
|
||||
private MLKEMParameters mlkemParams;
|
||||
|
||||
private SecureRandom random;
|
||||
|
||||
private void initialize(
|
||||
KeyGenerationParameters param)
|
||||
{
|
||||
this.mlkemParams = ((MLKEMKeyGenerationParameters)param).getParameters();
|
||||
this.random = param.getRandom();
|
||||
|
||||
}
|
||||
|
||||
private AsymmetricCipherKeyPair genKeyPair()
|
||||
{
|
||||
MLKEMEngine engine = mlkemParams.getEngine();
|
||||
|
||||
engine.init(random);
|
||||
|
||||
byte[][] keyPair = engine.generateKemKeyPair();
|
||||
|
||||
MLKEMPublicKeyParameters pubKey = new MLKEMPublicKeyParameters(mlkemParams, keyPair[0], keyPair[1]);
|
||||
MLKEMPrivateKeyParameters privKey = new MLKEMPrivateKeyParameters(mlkemParams, keyPair[2], keyPair[3], keyPair[4], keyPair[0], keyPair[1], keyPair[5]);
|
||||
|
||||
return new AsymmetricCipherKeyPair(pubKey, privKey);
|
||||
}
|
||||
|
||||
public void init(KeyGenerationParameters param)
|
||||
{
|
||||
this.initialize(param);
|
||||
}
|
||||
|
||||
public AsymmetricCipherKeyPair generateKeyPair()
|
||||
{
|
||||
return genKeyPair();
|
||||
}
|
||||
|
||||
public AsymmetricCipherKeyPair internalGenerateKeyPair(byte[] d, byte[] z)
|
||||
{
|
||||
byte[][] keyPair = mlkemParams.getEngine().generateKemKeyPairInternal(d, z);
|
||||
|
||||
MLKEMPublicKeyParameters pubKey = new MLKEMPublicKeyParameters(mlkemParams, keyPair[0], keyPair[1]);
|
||||
MLKEMPrivateKeyParameters privKey = new MLKEMPrivateKeyParameters(mlkemParams, keyPair[2], keyPair[3], keyPair[4], keyPair[0], keyPair[1], keyPair[5]);
|
||||
|
||||
return new AsymmetricCipherKeyPair(pubKey, privKey);
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package org.bouncycastle.pqc.crypto.mlkem;
|
||||
|
||||
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
|
||||
|
||||
public class MLKEMKeyParameters
|
||||
extends AsymmetricKeyParameter
|
||||
{
|
||||
private MLKEMParameters params;
|
||||
|
||||
public MLKEMKeyParameters(
|
||||
boolean isPrivate,
|
||||
MLKEMParameters params)
|
||||
{
|
||||
super(isPrivate);
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
public MLKEMParameters getParameters()
|
||||
{
|
||||
return params;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package org.bouncycastle.pqc.crypto.mlkem;
|
||||
|
||||
import org.bouncycastle.pqc.crypto.KEMParameters;
|
||||
|
||||
public class MLKEMParameters
|
||||
implements KEMParameters
|
||||
{
|
||||
public static final MLKEMParameters ml_kem_512 = new MLKEMParameters("ML-KEM-512", 2, 256);
|
||||
public static final MLKEMParameters ml_kem_768 = new MLKEMParameters("ML-KEM-768", 3, 256);
|
||||
public static final MLKEMParameters ml_kem_1024 = new MLKEMParameters("ML-KEM-1024", 4, 256);
|
||||
|
||||
private final String name;
|
||||
private final int k;
|
||||
private final int sessionKeySize;
|
||||
|
||||
private MLKEMParameters(String name, int k, int sessionKeySize)
|
||||
{
|
||||
this.name = name;
|
||||
this.k = k;
|
||||
this.sessionKeySize = sessionKeySize;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
public MLKEMEngine getEngine()
|
||||
{
|
||||
return new MLKEMEngine(k);
|
||||
}
|
||||
|
||||
public int getSessionKeySize()
|
||||
{
|
||||
return sessionKeySize;
|
||||
}
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
package org.bouncycastle.pqc.crypto.mlkem;
|
||||
|
||||
import org.bouncycastle.util.Arrays;
|
||||
|
||||
public class MLKEMPrivateKeyParameters
|
||||
extends MLKEMKeyParameters
|
||||
{
|
||||
final byte[] s;
|
||||
final byte[] hpk;
|
||||
final byte[] nonce;
|
||||
final byte[] t;
|
||||
final byte[] rho;
|
||||
final byte[] seed;
|
||||
|
||||
public MLKEMPrivateKeyParameters(MLKEMParameters params, byte[] s, byte[] hpk, byte[] nonce, byte[] t, byte[] rho)
|
||||
{
|
||||
this(params, s, hpk, nonce, t, rho, null);
|
||||
}
|
||||
|
||||
public MLKEMPrivateKeyParameters(MLKEMParameters params, byte[] s, byte[] hpk, byte[] nonce, byte[] t, byte[] rho, byte[] seed)
|
||||
{
|
||||
super(true, params);
|
||||
|
||||
this.s = Arrays.clone(s);
|
||||
this.hpk = Arrays.clone(hpk);
|
||||
this.nonce = Arrays.clone(nonce);
|
||||
this.t = Arrays.clone(t);
|
||||
this.rho = Arrays.clone(rho);
|
||||
this.seed = Arrays.clone(seed);
|
||||
}
|
||||
|
||||
public MLKEMPrivateKeyParameters(MLKEMParameters params, byte[] encoding)
|
||||
{
|
||||
super(true, params);
|
||||
|
||||
MLKEMEngine eng = params.getEngine();
|
||||
if (encoding.length == MLKEMEngine.KyberSymBytes * 2)
|
||||
{
|
||||
byte[][] keyData = eng.generateKemKeyPairInternal(
|
||||
Arrays.copyOfRange(encoding, 0, MLKEMEngine.KyberSymBytes),
|
||||
Arrays.copyOfRange(encoding, MLKEMEngine.KyberSymBytes, encoding.length));
|
||||
this.s = keyData[2];
|
||||
this.hpk = keyData[3];
|
||||
this.nonce = keyData[4];
|
||||
this.t = keyData[0];
|
||||
this.rho = keyData[1];
|
||||
this.seed = keyData[5];
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = 0;
|
||||
this.s = Arrays.copyOfRange(encoding, 0, eng.getKyberIndCpaSecretKeyBytes());
|
||||
index += eng.getKyberIndCpaSecretKeyBytes();
|
||||
this.t = Arrays.copyOfRange(encoding, index, index + eng.getKyberIndCpaPublicKeyBytes() - MLKEMEngine.KyberSymBytes);
|
||||
index += eng.getKyberIndCpaPublicKeyBytes() - MLKEMEngine.KyberSymBytes;
|
||||
this.rho = Arrays.copyOfRange(encoding, index, index + 32);
|
||||
index += 32;
|
||||
this.hpk = Arrays.copyOfRange(encoding, index, index + 32);
|
||||
index += 32;
|
||||
this.nonce = Arrays.copyOfRange(encoding, index, index + MLKEMEngine.KyberSymBytes);
|
||||
this.seed = null;
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] getEncoded()
|
||||
{
|
||||
return Arrays.concatenate(new byte[][]{ s, t, rho, hpk, nonce });
|
||||
}
|
||||
|
||||
public byte[] getHPK()
|
||||
{
|
||||
return Arrays.clone(hpk);
|
||||
}
|
||||
|
||||
public byte[] getNonce()
|
||||
{
|
||||
return Arrays.clone(nonce);
|
||||
}
|
||||
|
||||
public byte[] getPublicKey()
|
||||
{
|
||||
return MLKEMPublicKeyParameters.getEncoded(t, rho);
|
||||
}
|
||||
|
||||
public MLKEMPublicKeyParameters getPublicKeyParameters()
|
||||
{
|
||||
return new MLKEMPublicKeyParameters(getParameters(), t, rho);
|
||||
}
|
||||
|
||||
public byte[] getRho()
|
||||
{
|
||||
return Arrays.clone(rho);
|
||||
}
|
||||
|
||||
public byte[] getS()
|
||||
{
|
||||
return Arrays.clone(s);
|
||||
}
|
||||
|
||||
public byte[] getT()
|
||||
{
|
||||
return Arrays.clone(t);
|
||||
}
|
||||
|
||||
public byte[] getSeed()
|
||||
{
|
||||
return Arrays.clone(seed);
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package org.bouncycastle.pqc.crypto.mlkem;
|
||||
|
||||
import org.bouncycastle.util.Arrays;
|
||||
|
||||
public class MLKEMPublicKeyParameters
|
||||
extends MLKEMKeyParameters
|
||||
{
|
||||
static byte[] getEncoded(byte[] t, byte[] rho)
|
||||
{
|
||||
return Arrays.concatenate(t, rho);
|
||||
}
|
||||
|
||||
final byte[] t;
|
||||
final byte[] rho;
|
||||
|
||||
public MLKEMPublicKeyParameters(MLKEMParameters params, byte[] t, byte[] rho)
|
||||
{
|
||||
super(false, params);
|
||||
this.t = Arrays.clone(t);
|
||||
this.rho = Arrays.clone(rho);
|
||||
}
|
||||
|
||||
public MLKEMPublicKeyParameters(MLKEMParameters params, byte[] encoding)
|
||||
{
|
||||
super(false, params);
|
||||
this.t = Arrays.copyOfRange(encoding, 0, encoding.length - MLKEMEngine.KyberSymBytes);
|
||||
this.rho = Arrays.copyOfRange(encoding, encoding.length - MLKEMEngine.KyberSymBytes, encoding.length);
|
||||
}
|
||||
|
||||
public byte[] getEncoded()
|
||||
{
|
||||
return getEncoded(t, rho);
|
||||
}
|
||||
|
||||
public byte[] getRho()
|
||||
{
|
||||
return Arrays.clone(rho);
|
||||
}
|
||||
|
||||
public byte[] getT()
|
||||
{
|
||||
return Arrays.clone(t);
|
||||
}
|
||||
}
|
100
router/java/src/org/bouncycastle/pqc/crypto/mlkem/Ntt.java
Normal file
100
router/java/src/org/bouncycastle/pqc/crypto/mlkem/Ntt.java
Normal file
@ -0,0 +1,100 @@
|
||||
package org.bouncycastle.pqc.crypto.mlkem;
|
||||
|
||||
class Ntt
|
||||
{
|
||||
|
||||
public static final short[] nttZetas = new short[]{
|
||||
2285, 2571, 2970, 1812, 1493, 1422, 287, 202, 3158, 622, 1577, 182, 962,
|
||||
2127, 1855, 1468, 573, 2004, 264, 383, 2500, 1458, 1727, 3199, 2648, 1017,
|
||||
732, 608, 1787, 411, 3124, 1758, 1223, 652, 2777, 1015, 2036, 1491, 3047,
|
||||
1785, 516, 3321, 3009, 2663, 1711, 2167, 126, 1469, 2476, 3239, 3058, 830,
|
||||
107, 1908, 3082, 2378, 2931, 961, 1821, 2604, 448, 2264, 677, 2054, 2226,
|
||||
430, 555, 843, 2078, 871, 1550, 105, 422, 587, 177, 3094, 3038, 2869, 1574,
|
||||
1653, 3083, 778, 1159, 3182, 2552, 1483, 2727, 1119, 1739, 644, 2457, 349,
|
||||
418, 329, 3173, 3254, 817, 1097, 603, 610, 1322, 2044, 1864, 384, 2114, 3193,
|
||||
1218, 1994, 2455, 220, 2142, 1670, 2144, 1799, 2051, 794, 1819, 2475, 2459,
|
||||
478, 3221, 3021, 996, 991, 958, 1869, 1522, 1628};
|
||||
|
||||
public static final short[] nttZetasInv = new short[]{
|
||||
1701, 1807, 1460, 2371, 2338, 2333, 308, 108, 2851, 870, 854, 1510, 2535,
|
||||
1278, 1530, 1185, 1659, 1187, 3109, 874, 1335, 2111, 136, 1215, 2945, 1465,
|
||||
1285, 2007, 2719, 2726, 2232, 2512, 75, 156, 3000, 2911, 2980, 872, 2685,
|
||||
1590, 2210, 602, 1846, 777, 147, 2170, 2551, 246, 1676, 1755, 460, 291, 235,
|
||||
3152, 2742, 2907, 3224, 1779, 2458, 1251, 2486, 2774, 2899, 1103, 1275, 2652,
|
||||
1065, 2881, 725, 1508, 2368, 398, 951, 247, 1421, 3222, 2499, 271, 90, 853,
|
||||
1860, 3203, 1162, 1618, 666, 320, 8, 2813, 1544, 282, 1838, 1293, 2314, 552,
|
||||
2677, 2106, 1571, 205, 2918, 1542, 2721, 2597, 2312, 681, 130, 1602, 1871,
|
||||
829, 2946, 3065, 1325, 2756, 1861, 1474, 1202, 2367, 3147, 1752, 2707, 171,
|
||||
3127, 3042, 1907, 1836, 1517, 359, 758, 1441};
|
||||
|
||||
public static short[] ntt(short[] inp)
|
||||
{
|
||||
short[] r = new short[MLKEMEngine.KyberN];
|
||||
System.arraycopy(inp, 0, r, 0, r.length);
|
||||
int len, start, j, k;
|
||||
short t, zeta;
|
||||
|
||||
k = 1;
|
||||
for (len = 128; len >= 2; len >>= 1)
|
||||
{
|
||||
for (start = 0; start < 256; start = j + len)
|
||||
{
|
||||
zeta = nttZetas[k++];
|
||||
for (j = start; j < start + len; ++j)
|
||||
{
|
||||
t = factorQMulMont(zeta, r[j + len]);
|
||||
r[j + len] = (short)(r[j] - t);
|
||||
r[j] = (short)(r[j] + t);
|
||||
}
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
public static short[] invNtt(short[] inp)
|
||||
{
|
||||
short[] r = new short[MLKEMEngine.KyberN];
|
||||
System.arraycopy(inp, 0, r, 0, MLKEMEngine.KyberN);
|
||||
int len, start, j, k;
|
||||
short t, zeta;
|
||||
k = 0;
|
||||
for (len = 2; len <= 128; len <<= 1)
|
||||
{
|
||||
for (start = 0; start < 256; start = j + len)
|
||||
{
|
||||
zeta = nttZetasInv[k++];
|
||||
for (j = start; j < start + len; ++j)
|
||||
{
|
||||
t = r[j];
|
||||
r[j] = Reduce.barretReduce((short)(t + r[j + len]));
|
||||
r[j + len] = (short)(t - r[j + len]);
|
||||
r[j + len] = factorQMulMont(zeta, r[j + len]);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (j = 0; j < 256; ++j)
|
||||
{
|
||||
r[j] = factorQMulMont(r[j], Ntt.nttZetasInv[127]);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
public static short factorQMulMont(short a, short b)
|
||||
{
|
||||
return Reduce.montgomeryReduce((int)(a * b));
|
||||
}
|
||||
|
||||
public static void baseMult(Poly outPoly, int outIndex, short a0, short a1, short b0, short b1, short zeta)
|
||||
{
|
||||
short outVal0 = factorQMulMont(a1, b1);
|
||||
outVal0 = factorQMulMont(outVal0, zeta);
|
||||
outVal0 += factorQMulMont(a0, b0);
|
||||
outPoly.setCoeffIndex(outIndex, outVal0);
|
||||
|
||||
short outVal1 = factorQMulMont(a0, b1);
|
||||
outVal1 += factorQMulMont(a1, b0);
|
||||
outPoly.setCoeffIndex(outIndex + 1, outVal1);
|
||||
}
|
||||
}
|
354
router/java/src/org/bouncycastle/pqc/crypto/mlkem/Poly.java
Normal file
354
router/java/src/org/bouncycastle/pqc/crypto/mlkem/Poly.java
Normal file
@ -0,0 +1,354 @@
|
||||
package org.bouncycastle.pqc.crypto.mlkem;
|
||||
|
||||
class Poly
|
||||
{
|
||||
private short[] coeffs;
|
||||
private MLKEMEngine engine;
|
||||
private int polyCompressedBytes;
|
||||
private int eta1;
|
||||
private int eta2;
|
||||
|
||||
private Symmetric symmetric;
|
||||
|
||||
public Poly(MLKEMEngine engine)
|
||||
{
|
||||
this.coeffs = new short[MLKEMEngine.KyberN];
|
||||
this.engine = engine;
|
||||
polyCompressedBytes = engine.getKyberPolyCompressedBytes();
|
||||
this.eta1 = engine.getKyberEta1();
|
||||
this.eta2 = MLKEMEngine.getKyberEta2();
|
||||
this.symmetric = engine.getSymmetric();
|
||||
}
|
||||
|
||||
public short getCoeffIndex(int i)
|
||||
{
|
||||
return this.coeffs[i];
|
||||
}
|
||||
|
||||
public short[] getCoeffs()
|
||||
{
|
||||
return this.coeffs;
|
||||
}
|
||||
|
||||
public void setCoeffIndex(int i, short val)
|
||||
{
|
||||
this.coeffs[i] = val;
|
||||
}
|
||||
|
||||
public void setCoeffs(short[] coeffs)
|
||||
{
|
||||
this.coeffs = coeffs;
|
||||
}
|
||||
|
||||
public void polyNtt()
|
||||
{
|
||||
this.setCoeffs(Ntt.ntt(this.getCoeffs()));
|
||||
this.reduce();
|
||||
}
|
||||
|
||||
public void polyInverseNttToMont()
|
||||
{
|
||||
this.setCoeffs(Ntt.invNtt(this.getCoeffs()));
|
||||
}
|
||||
|
||||
public void reduce()
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < MLKEMEngine.KyberN; i++)
|
||||
{
|
||||
this.setCoeffIndex(i, Reduce.barretReduce(this.getCoeffIndex(i)));
|
||||
}
|
||||
}
|
||||
|
||||
public static void baseMultMontgomery(Poly r, Poly a, Poly b)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < MLKEMEngine.KyberN / 4; i++)
|
||||
{
|
||||
Ntt.baseMult(r, 4 * i,
|
||||
a.getCoeffIndex(4 * i), a.getCoeffIndex(4 * i + 1),
|
||||
b.getCoeffIndex(4 * i), b.getCoeffIndex(4 * i + 1),
|
||||
Ntt.nttZetas[64 + i]);
|
||||
Ntt.baseMult(r, 4 * i + 2,
|
||||
a.getCoeffIndex(4 * i + 2), a.getCoeffIndex(4 * i + 3),
|
||||
b.getCoeffIndex(4 * i + 2), b.getCoeffIndex(4 * i + 3),
|
||||
(short)(-1 * Ntt.nttZetas[64 + i]));
|
||||
}
|
||||
}
|
||||
|
||||
public void addCoeffs(Poly b)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < MLKEMEngine.KyberN; i++)
|
||||
{
|
||||
this.setCoeffIndex(i, (short)(this.getCoeffIndex(i) + b.getCoeffIndex(i)));
|
||||
}
|
||||
}
|
||||
|
||||
public void convertToMont()
|
||||
{
|
||||
int i;
|
||||
final short f = (short)(((long)1 << 32) % MLKEMEngine.KyberQ);
|
||||
for (i = 0; i < MLKEMEngine.KyberN; i++)
|
||||
{
|
||||
this.setCoeffIndex(i, Reduce.montgomeryReduce(this.getCoeffIndex(i) * f));
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] compressPoly()
|
||||
{
|
||||
int i, j;
|
||||
byte[] t = new byte[8];
|
||||
byte[] r = new byte[polyCompressedBytes];
|
||||
int count = 0;
|
||||
this.conditionalSubQ();
|
||||
|
||||
// System.out.print("v = [");
|
||||
// Helper.printShortArray(this.coeffs);
|
||||
// System.out.print("]\n");
|
||||
|
||||
if (polyCompressedBytes == 128)
|
||||
{
|
||||
for (i = 0; i < MLKEMEngine.KyberN / 8; i++)
|
||||
{
|
||||
for (j = 0; j < 8; j++)
|
||||
{
|
||||
/*t[j] =
|
||||
(byte)((((((short)this.getCoeffIndex(8 * i + j)) << 4)
|
||||
+
|
||||
(KyberEngine.KyberQ / 2)
|
||||
) / KyberEngine.KyberQ)
|
||||
& 15);*/
|
||||
// Fix for KyberSlash2: division by KyberQ above is not
|
||||
// constant time.
|
||||
int t_j = this.getCoeffIndex(8 * i + j);
|
||||
t_j <<= 4;
|
||||
t_j += 1665;
|
||||
t_j *= 80635;
|
||||
t_j >>= 28;
|
||||
t_j &= 15;
|
||||
t[j] = (byte)t_j;
|
||||
}
|
||||
|
||||
r[count + 0] = (byte)(t[0] | (t[1] << 4));
|
||||
r[count + 1] = (byte)(t[2] | (t[3] << 4));
|
||||
r[count + 2] = (byte)(t[4] | (t[5] << 4));
|
||||
r[count + 3] = (byte)(t[6] | (t[7] << 4));
|
||||
count += 4;
|
||||
}
|
||||
}
|
||||
else if (polyCompressedBytes == 160)
|
||||
{
|
||||
for (i = 0; i < MLKEMEngine.KyberN / 8; i++)
|
||||
{
|
||||
for (j = 0; j < 8; j++)
|
||||
{
|
||||
/*t[j] =
|
||||
(byte)(((((this.getCoeffIndex(8 * i + j) << 5))
|
||||
+
|
||||
(KyberEngine.KyberQ / 2)
|
||||
) / KyberEngine.KyberQ
|
||||
) & 31
|
||||
);*/
|
||||
// Fix for KyberSlash2: division by KyberQ above is not
|
||||
// constant time.
|
||||
int t_j = this.getCoeffIndex(8 * i + j);
|
||||
t_j <<= 5;
|
||||
t_j += 1664;
|
||||
t_j *= 40318;
|
||||
t_j >>= 27;
|
||||
t_j &= 31;
|
||||
t[j] = (byte)t_j;
|
||||
}
|
||||
r[count + 0] = (byte)((t[0] >> 0) | (t[1] << 5));
|
||||
r[count + 1] = (byte)((t[1] >> 3) | (t[2] << 2) | (t[3] << 7));
|
||||
r[count + 2] = (byte)((t[3] >> 1) | (t[4] << 4));
|
||||
r[count + 3] = (byte)((t[4] >> 4) | (t[5] << 1) | (t[6] << 6));
|
||||
r[count + 4] = (byte)((t[6] >> 2) | (t[7] << 3));
|
||||
count += 5;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException("PolyCompressedBytes is neither 128 or 160!");
|
||||
}
|
||||
|
||||
// System.out.print("r = ");
|
||||
// Helper.printByteArray(r);
|
||||
// System.out.println();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
public void decompressPoly(byte[] compressedPolyCipherText)
|
||||
{
|
||||
int i, count = 0;
|
||||
|
||||
if (engine.getKyberPolyCompressedBytes() == 128)
|
||||
{
|
||||
for (i = 0; i < MLKEMEngine.KyberN / 2; i++)
|
||||
{
|
||||
this.setCoeffIndex(2 * i + 0, (short)((((short)((compressedPolyCipherText[count] & 0xFF) & 15) * MLKEMEngine.KyberQ) + 8) >> 4));
|
||||
this.setCoeffIndex(2 * i + 1, (short)((((short)((compressedPolyCipherText[count] & 0xFF) >> 4) * MLKEMEngine.KyberQ) + 8) >> 4));
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
else if (engine.getKyberPolyCompressedBytes() == 160)
|
||||
{
|
||||
int j;
|
||||
byte[] t = new byte[8];
|
||||
for (i = 0; i < MLKEMEngine.KyberN / 8; i++)
|
||||
{
|
||||
t[0] = (byte)((compressedPolyCipherText[count + 0] & 0xFF) >> 0);
|
||||
t[1] = (byte)(((compressedPolyCipherText[count + 0] & 0xFF) >> 5) | ((compressedPolyCipherText[count + 1] & 0xFF) << 3));
|
||||
t[2] = (byte)((compressedPolyCipherText[count + 1] & 0xFF) >> 2);
|
||||
t[3] = (byte)(((compressedPolyCipherText[count + 1] & 0xFF) >> 7) | ((compressedPolyCipherText[count + 2] & 0xFF) << 1));
|
||||
t[4] = (byte)(((compressedPolyCipherText[count + 2] & 0xFF) >> 4) | ((compressedPolyCipherText[count + 3] & 0xFF) << 4));
|
||||
t[5] = (byte)((compressedPolyCipherText[count + 3] & 0xFF) >> 1);
|
||||
t[6] = (byte)(((compressedPolyCipherText[count + 3] & 0xFF) >> 6) | ((compressedPolyCipherText[count + 4] & 0xFF) << 2));
|
||||
t[7] = (byte)((compressedPolyCipherText[count + 4] & 0xFF) >> 3);
|
||||
count += 5;
|
||||
for (j = 0; j < 8; j++)
|
||||
{
|
||||
this.setCoeffIndex(8 * i + j, (short)(((t[j] & 31) * MLKEMEngine.KyberQ + 16) >> 5));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException("PolyCompressedBytes is neither 128 or 160!");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public byte[] toBytes()
|
||||
{
|
||||
byte[] r = new byte[MLKEMEngine.KyberPolyBytes];
|
||||
short t0, t1;
|
||||
this.conditionalSubQ();
|
||||
for (int i = 0; i < MLKEMEngine.KyberN / 2; i++)
|
||||
{
|
||||
t0 = this.getCoeffIndex(2 * i);
|
||||
t1 = this.getCoeffIndex(2 * i + 1);
|
||||
r[3 * i] = (byte)(t0 >> 0);
|
||||
r[3 * i + 1] = (byte)((t0 >> 8) | (t1 << 4));
|
||||
r[3 * i + 2] = (byte)(t1 >> 4);
|
||||
}
|
||||
|
||||
return r;
|
||||
|
||||
}
|
||||
|
||||
public void fromBytes(byte[] inpBytes)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < MLKEMEngine.KyberN / 2; i++)
|
||||
{
|
||||
this.setCoeffIndex(2 * i, (short)(
|
||||
(
|
||||
((inpBytes[3 * i + 0] & 0xFF) >> 0)
|
||||
| ((inpBytes[3 * i + 1] & 0xFF) << 8)
|
||||
) & 0xFFF)
|
||||
);
|
||||
this.setCoeffIndex(2 * i + 1, (short)(
|
||||
(
|
||||
((inpBytes[3 * i + 1] & 0xFF) >> 4)
|
||||
| (long)((inpBytes[3 * i + 2] & 0xFF) << 4)
|
||||
) & 0xFFF)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] toMsg()
|
||||
{
|
||||
int LOWER = MLKEMEngine.KyberQ >>> 2;
|
||||
int UPPER = MLKEMEngine.KyberQ - LOWER;
|
||||
|
||||
byte[] outMsg = new byte[MLKEMEngine.getKyberIndCpaMsgBytes()];
|
||||
|
||||
this.conditionalSubQ();
|
||||
|
||||
for (int i = 0; i < MLKEMEngine.KyberN / 8; i++)
|
||||
{
|
||||
outMsg[i] = 0;
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
int c_j = this.getCoeffIndex(8 * i + j);
|
||||
|
||||
// KyberSlash: division by Q is not constant time.
|
||||
// int t = (((c_j << 1) + (KyberEngine.KyberQ / 2)) / KyberEngine.KyberQ) & 1;
|
||||
int t = ((LOWER - c_j) & (c_j - UPPER)) >>> 31;
|
||||
|
||||
outMsg[i] |= (byte)(t << j);
|
||||
}
|
||||
}
|
||||
return outMsg;
|
||||
}
|
||||
|
||||
public void fromMsg(byte[] msg)
|
||||
{
|
||||
int i, j;
|
||||
short mask;
|
||||
if (msg.length != MLKEMEngine.KyberN / 8)
|
||||
{
|
||||
throw new RuntimeException("KYBER_INDCPA_MSGBYTES must be equal to KYBER_N/8 bytes!");
|
||||
}
|
||||
for (i = 0; i < MLKEMEngine.KyberN / 8; i++)
|
||||
{
|
||||
for (j = 0; j < 8; j++)
|
||||
{
|
||||
mask = (short)((-1) * (short)(((msg[i] & 0xFF) >> j) & 1));
|
||||
this.setCoeffIndex(8 * i + j, (short)(mask & (short)((MLKEMEngine.KyberQ + 1) / 2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void conditionalSubQ()
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < MLKEMEngine.KyberN; i++)
|
||||
{
|
||||
this.setCoeffIndex(i, Reduce.conditionalSubQ(this.getCoeffIndex(i)));
|
||||
}
|
||||
}
|
||||
|
||||
public void getEta1Noise(byte[] seed, byte nonce)
|
||||
{
|
||||
byte[] buf = new byte[MLKEMEngine.KyberN * eta1 / 4];
|
||||
symmetric.prf(buf, seed, nonce);
|
||||
CBD.mlkemCBD(this, buf, eta1);
|
||||
}
|
||||
|
||||
public void getEta2Noise(byte[] seed, byte nonce)
|
||||
{
|
||||
byte[] buf = new byte[MLKEMEngine.KyberN * eta2 / 4];
|
||||
symmetric.prf(buf, seed, nonce);
|
||||
CBD.mlkemCBD(this, buf, eta2);
|
||||
}
|
||||
|
||||
public void polySubtract(Poly b)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < MLKEMEngine.KyberN; i++)
|
||||
{
|
||||
this.setCoeffIndex(i, (short)(b.getCoeffIndex(i) - this.getCoeffIndex(i)));
|
||||
}
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
StringBuffer out = new StringBuffer();
|
||||
out.append("[");
|
||||
for (int i = 0; i < coeffs.length; i++)
|
||||
{
|
||||
out.append(coeffs[i]);
|
||||
if (i != coeffs.length - 1)
|
||||
{
|
||||
out.append(", ");
|
||||
}
|
||||
}
|
||||
out.append("]");
|
||||
return out.toString();
|
||||
}
|
||||
}
|
||||
|
272
router/java/src/org/bouncycastle/pqc/crypto/mlkem/PolyVec.java
Normal file
272
router/java/src/org/bouncycastle/pqc/crypto/mlkem/PolyVec.java
Normal file
@ -0,0 +1,272 @@
|
||||
package org.bouncycastle.pqc.crypto.mlkem;
|
||||
|
||||
import org.bouncycastle.util.Arrays;
|
||||
|
||||
class PolyVec
|
||||
{
|
||||
Poly[] vec;
|
||||
private MLKEMEngine engine;
|
||||
private int kyberK;
|
||||
private int polyVecBytes;
|
||||
|
||||
public PolyVec(MLKEMEngine engine)
|
||||
{
|
||||
this.engine = engine;
|
||||
this.kyberK = engine.getKyberK();
|
||||
this.polyVecBytes = engine.getKyberPolyVecBytes();
|
||||
|
||||
this.vec = new Poly[kyberK];
|
||||
for (int i = 0; i < kyberK; i++)
|
||||
{
|
||||
vec[i] = new Poly(engine);
|
||||
}
|
||||
}
|
||||
|
||||
public PolyVec()
|
||||
throws Exception
|
||||
{
|
||||
throw new Exception("Requires Parameter");
|
||||
}
|
||||
|
||||
public Poly getVectorIndex(int i)
|
||||
{
|
||||
return vec[i];
|
||||
}
|
||||
|
||||
public void polyVecNtt()
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < kyberK; i++)
|
||||
{
|
||||
this.getVectorIndex(i).polyNtt();
|
||||
}
|
||||
}
|
||||
|
||||
public void polyVecInverseNttToMont()
|
||||
{
|
||||
for (int i = 0; i < kyberK; i++)
|
||||
{
|
||||
this.getVectorIndex(i).polyInverseNttToMont();
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] compressPolyVec()
|
||||
{
|
||||
int i, j, k;
|
||||
|
||||
this.conditionalSubQ();
|
||||
short[] t;
|
||||
byte[] r = new byte[engine.getKyberPolyVecCompressedBytes()];
|
||||
int count = 0;
|
||||
if (engine.getKyberPolyVecCompressedBytes() == kyberK * 320)
|
||||
{
|
||||
t = new short[4];
|
||||
for (i = 0; i < kyberK; i++)
|
||||
{
|
||||
for (j = 0; j < MLKEMEngine.KyberN / 4; j++)
|
||||
{
|
||||
for (k = 0; k < 4; k++)
|
||||
{
|
||||
/*t[k] = (short)
|
||||
(
|
||||
(
|
||||
((this.getVectorIndex(i).getCoeffIndex(4 * j + k) << 10)
|
||||
+ (KyberEngine.KyberQ / 2))
|
||||
/ KyberEngine.KyberQ)
|
||||
& 0x3ff);*/
|
||||
// Fix for KyberSlash2: division by KyberQ above is not
|
||||
// constant time.
|
||||
long t_k = this.getVectorIndex(i).getCoeffIndex(4 * j + k);
|
||||
t_k <<= 10;
|
||||
t_k += 1665;
|
||||
t_k *= 1290167;
|
||||
t_k >>= 32;
|
||||
t_k &= 0x3ff;
|
||||
t[k] = (short)t_k;
|
||||
}
|
||||
r[count + 0] = (byte)(t[0] >> 0);
|
||||
r[count + 1] = (byte)((t[0] >> 8) | (t[1] << 2));
|
||||
r[count + 2] = (byte)((t[1] >> 6) | (t[2] << 4));
|
||||
r[count + 3] = (byte)((t[2] >> 4) | (t[3] << 6));
|
||||
r[count + 4] = (byte)((t[3] >> 2));
|
||||
count += 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (engine.getKyberPolyVecCompressedBytes() == kyberK * 352)
|
||||
{
|
||||
t = new short[8];
|
||||
for (i = 0; i < kyberK; i++)
|
||||
{
|
||||
for (j = 0; j < MLKEMEngine.KyberN / 8; j++)
|
||||
{
|
||||
for (k = 0; k < 8; k++)
|
||||
{
|
||||
/*t[k] = (short)
|
||||
(
|
||||
(
|
||||
((this.getVectorIndex(i).getCoeffIndex(8 * j + k) << 11)
|
||||
+ (KyberEngine.KyberQ / 2))
|
||||
/ KyberEngine.KyberQ)
|
||||
& 0x7ff);*/
|
||||
// Fix for KyberSlash2: division by KyberQ above is not
|
||||
// constant time.
|
||||
long t_k = this.getVectorIndex(i).getCoeffIndex(8 * j + k);
|
||||
t_k <<= 11;
|
||||
t_k += 1664;
|
||||
t_k *= 645084;
|
||||
t_k >>= 31;
|
||||
t_k &= 0x7ff;
|
||||
t[k] = (short)t_k;
|
||||
}
|
||||
r[count + 0] = (byte)((t[0] >> 0));
|
||||
r[count + 1] = (byte)((t[0] >> 8) | (t[1] << 3));
|
||||
r[count + 2] = (byte)((t[1] >> 5) | (t[2] << 6));
|
||||
r[count + 3] = (byte)((t[2] >> 2));
|
||||
r[count + 4] = (byte)((t[2] >> 10) | (t[3] << 1));
|
||||
r[count + 5] = (byte)((t[3] >> 7) | (t[4] << 4));
|
||||
r[count + 6] = (byte)((t[4] >> 4) | (t[5] << 7));
|
||||
r[count + 7] = (byte)((t[5] >> 1));
|
||||
r[count + 8] = (byte)((t[5] >> 9) | (t[6] << 2));
|
||||
r[count + 9] = (byte)((t[6] >> 6) | (t[7] << 5));
|
||||
r[count + 10] = (byte)((t[7] >> 3));
|
||||
count += 11;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException("Kyber PolyVecCompressedBytes neither 320 * KyberK or 352 * KyberK!");
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
public void decompressPolyVec(byte[] compressedPolyVecCipherText)
|
||||
{
|
||||
int i, j, k, count = 0;
|
||||
|
||||
if (engine.getKyberPolyVecCompressedBytes() == (kyberK * 320))
|
||||
{
|
||||
short[] t = new short[4];
|
||||
for (i = 0; i < kyberK; i++)
|
||||
{
|
||||
for (j = 0; j < MLKEMEngine.KyberN / 4; j++)
|
||||
{
|
||||
t[0] = (short)(((compressedPolyVecCipherText[count] & 0xFF) >> 0) | (short)((compressedPolyVecCipherText[count + 1] & 0xFF) << 8));
|
||||
t[1] = (short)(((compressedPolyVecCipherText[count + 1] & 0xFF) >> 2) | (short)((compressedPolyVecCipherText[count + 2] & 0xFF) << 6));
|
||||
t[2] = (short)(((compressedPolyVecCipherText[count + 2] & 0xFF) >> 4) | (short)((compressedPolyVecCipherText[count + 3] & 0xFF) << 4));
|
||||
t[3] = (short)(((compressedPolyVecCipherText[count + 3] & 0xFF) >> 6) | (short)((compressedPolyVecCipherText[count + 4] & 0xFF) << 2));
|
||||
count += 5;
|
||||
for (k = 0; k < 4; k++)
|
||||
{
|
||||
this.vec[i].setCoeffIndex(4 * j + k, (short)(((t[k] & 0x3FF) * MLKEMEngine.KyberQ + 512) >> 10));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else if (engine.getKyberPolyVecCompressedBytes() == (kyberK * 352))
|
||||
{
|
||||
short[] t = new short[8];
|
||||
for (i = 0; i < kyberK; i++)
|
||||
{
|
||||
for (j = 0; j < MLKEMEngine.KyberN / 8; j++)
|
||||
{
|
||||
t[0] = (short)(((compressedPolyVecCipherText[count] & 0xFF) >> 0) | ((short)(compressedPolyVecCipherText[count + 1] & 0xFF) << 8));
|
||||
t[1] = (short)(((compressedPolyVecCipherText[count + 1] & 0xFF) >> 3) | ((short)(compressedPolyVecCipherText[count + 2] & 0xFF) << 5));
|
||||
t[2] = (short)(((compressedPolyVecCipherText[count + 2] & 0xFF) >> 6) | ((short)(compressedPolyVecCipherText[count + 3] & 0xFF) << 2) | ((short)((compressedPolyVecCipherText[count + 4] & 0xFF) << 10)));
|
||||
t[3] = (short)(((compressedPolyVecCipherText[count + 4] & 0xFF) >> 1) | ((short)(compressedPolyVecCipherText[count + 5] & 0xFF) << 7));
|
||||
t[4] = (short)(((compressedPolyVecCipherText[count + 5] & 0xFF) >> 4) | ((short)(compressedPolyVecCipherText[count + 6] & 0xFF) << 4));
|
||||
t[5] = (short)(((compressedPolyVecCipherText[count + 6] & 0xFF) >> 7) | ((short)(compressedPolyVecCipherText[count + 7] & 0xFF) << 1) | ((short)((compressedPolyVecCipherText[count + 8] & 0xFF) << 9)));
|
||||
t[6] = (short)(((compressedPolyVecCipherText[count + 8] & 0xFF) >> 2) | ((short)(compressedPolyVecCipherText[count + 9] & 0xFF) << 6));
|
||||
t[7] = (short)(((compressedPolyVecCipherText[count + 9] & 0xFF) >> 5) | ((short)(compressedPolyVecCipherText[count + 10] & 0xFF) << 3));
|
||||
count += 11;
|
||||
for (k = 0; k < 8; k++)
|
||||
{
|
||||
this.vec[i].setCoeffIndex(8 * j + k, (short)(((t[k] & 0x7FF) * MLKEMEngine.KyberQ + 1024) >> 11));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException("Kyber PolyVecCompressedBytes neither 320 * KyberK or 352 * KyberK!");
|
||||
}
|
||||
}
|
||||
|
||||
public static void pointwiseAccountMontgomery(Poly out, PolyVec inp1, PolyVec inp2, MLKEMEngine engine)
|
||||
{
|
||||
int i;
|
||||
Poly t = new Poly(engine);
|
||||
|
||||
Poly.baseMultMontgomery(out, inp1.getVectorIndex(0), inp2.getVectorIndex(0));
|
||||
for (i = 1; i < engine.getKyberK(); i++)
|
||||
{
|
||||
Poly.baseMultMontgomery(t, inp1.getVectorIndex(i), inp2.getVectorIndex(i));
|
||||
out.addCoeffs(t);
|
||||
}
|
||||
out.reduce();
|
||||
}
|
||||
|
||||
public void reducePoly()
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < kyberK; i++)
|
||||
{
|
||||
this.getVectorIndex(i).reduce();
|
||||
}
|
||||
}
|
||||
|
||||
public void addPoly(PolyVec b)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < kyberK; i++)
|
||||
{
|
||||
this.getVectorIndex(i).addCoeffs(b.getVectorIndex(i));
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] toBytes()
|
||||
{
|
||||
byte[] r = new byte[polyVecBytes];
|
||||
for (int i = 0; i < kyberK; i++)
|
||||
{
|
||||
System.arraycopy(this.vec[i].toBytes(), 0, r, i * MLKEMEngine.KyberPolyBytes, MLKEMEngine.KyberPolyBytes);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
public void fromBytes(byte[] inputBytes)
|
||||
{
|
||||
for (int i = 0; i < kyberK; i++)
|
||||
{
|
||||
this.getVectorIndex(i).fromBytes(Arrays.copyOfRange(inputBytes, i * MLKEMEngine.KyberPolyBytes, (i + 1) * MLKEMEngine.KyberPolyBytes));
|
||||
}
|
||||
}
|
||||
|
||||
public void conditionalSubQ()
|
||||
{
|
||||
for (int i = 0; i < kyberK; i++)
|
||||
{
|
||||
this.getVectorIndex(i).conditionalSubQ();
|
||||
}
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
StringBuffer out = new StringBuffer();
|
||||
out.append("[");
|
||||
for (int i = 0; i < kyberK; i++)
|
||||
{
|
||||
out.append(vec[i].toString());
|
||||
if (i != kyberK - 1)
|
||||
{
|
||||
out.append(", ");
|
||||
}
|
||||
}
|
||||
out.append("]");
|
||||
return out.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package org.bouncycastle.pqc.crypto.mlkem;
|
||||
|
||||
class Reduce
|
||||
{
|
||||
|
||||
public static short montgomeryReduce(int a)
|
||||
{
|
||||
int t;
|
||||
short u;
|
||||
|
||||
u = (short)(a * MLKEMEngine.KyberQinv);
|
||||
t = (int)(u * MLKEMEngine.KyberQ);
|
||||
t = a - t;
|
||||
t >>= 16;
|
||||
return (short)t;
|
||||
}
|
||||
|
||||
public static short barretReduce(short a)
|
||||
{
|
||||
short t;
|
||||
long shift = (((long)1) << 26);
|
||||
short v = (short)((shift + (MLKEMEngine.KyberQ / 2)) / MLKEMEngine.KyberQ);
|
||||
t = (short)((v * a) >> 26);
|
||||
t = (short)(t * MLKEMEngine.KyberQ);
|
||||
return (short)(a - t);
|
||||
}
|
||||
|
||||
public static short conditionalSubQ(short a)
|
||||
{
|
||||
a -= MLKEMEngine.KyberQ;
|
||||
a += (a >> 15) & MLKEMEngine.KyberQ;
|
||||
return a;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
package org.bouncycastle.pqc.crypto.mlkem;
|
||||
|
||||
import org.bouncycastle.crypto.digests.SHA3Digest;
|
||||
import org.bouncycastle.crypto.digests.SHAKEDigest;
|
||||
|
||||
abstract class Symmetric
|
||||
{
|
||||
|
||||
final int xofBlockBytes;
|
||||
|
||||
abstract void hash_h(byte[] out, byte[] in, int outOffset);
|
||||
|
||||
abstract void hash_g(byte[] out, byte[] in);
|
||||
|
||||
abstract void xofAbsorb(byte[] seed, byte x, byte y);
|
||||
|
||||
abstract void xofSqueezeBlocks(byte[] out, int outOffset, int outLen);
|
||||
|
||||
abstract void prf(byte[] out, byte[] key, byte nonce);
|
||||
|
||||
abstract void kdf(byte[] out, byte[] in);
|
||||
|
||||
Symmetric(int blockBytes)
|
||||
{
|
||||
this.xofBlockBytes = blockBytes;
|
||||
}
|
||||
|
||||
|
||||
static class ShakeSymmetric
|
||||
extends Symmetric
|
||||
{
|
||||
private final SHAKEDigest xof;
|
||||
private final SHA3Digest sha3Digest512;
|
||||
private final SHA3Digest sha3Digest256;
|
||||
private final SHAKEDigest shakeDigest;
|
||||
|
||||
ShakeSymmetric()
|
||||
{
|
||||
super(168);
|
||||
this.xof = new SHAKEDigest(128);
|
||||
this.shakeDigest = new SHAKEDigest(256);
|
||||
this.sha3Digest256 = new SHA3Digest(256);
|
||||
this.sha3Digest512 = new SHA3Digest(512);
|
||||
}
|
||||
|
||||
@Override
|
||||
void hash_h(byte[] out, byte[] in, int outOffset)
|
||||
{
|
||||
sha3Digest256.update(in, 0, in.length);
|
||||
sha3Digest256.doFinal(out, outOffset);
|
||||
}
|
||||
|
||||
@Override
|
||||
void hash_g(byte[] out, byte[] in)
|
||||
{
|
||||
sha3Digest512.update(in, 0, in.length);
|
||||
sha3Digest512.doFinal(out, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
void xofAbsorb(byte[] seed, byte a, byte b)
|
||||
{
|
||||
xof.reset();
|
||||
byte[] buf = new byte[seed.length + 2];
|
||||
System.arraycopy(seed, 0, buf, 0, seed.length);
|
||||
buf[seed.length] = a;
|
||||
buf[seed.length + 1] = b;
|
||||
xof.update(buf, 0, seed.length + 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
void xofSqueezeBlocks(byte[] out, int outOffset, int outLen)
|
||||
{
|
||||
xof.doOutput(out, outOffset, outLen);
|
||||
}
|
||||
|
||||
@Override
|
||||
void prf(byte[] out, byte[] seed, byte nonce)
|
||||
{
|
||||
byte[] extSeed = new byte[seed.length + 1];
|
||||
System.arraycopy(seed, 0, extSeed, 0, seed.length);
|
||||
extSeed[seed.length] = nonce;
|
||||
shakeDigest.update(extSeed, 0, extSeed.length);
|
||||
shakeDigest.doFinal(out, 0, out.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
void kdf(byte[] out, byte[] in)
|
||||
{
|
||||
shakeDigest.update(in, 0, in.length);
|
||||
shakeDigest.doFinal(out, 0, out.length);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package org.bouncycastle.pqc.crypto.util;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import javax.security.auth.DestroyFailedException;
|
||||
|
||||
import org.bouncycastle.crypto.SecretWithEncapsulation;
|
||||
import org.bouncycastle.util.Arrays;
|
||||
|
||||
public class SecretWithEncapsulationImpl
|
||||
implements SecretWithEncapsulation
|
||||
{
|
||||
private final AtomicBoolean hasBeenDestroyed = new AtomicBoolean(false);
|
||||
|
||||
private final byte[] sessionKey;
|
||||
private final byte[] cipher_text;
|
||||
|
||||
public SecretWithEncapsulationImpl(byte[] sessionKey, byte[] cipher_text)
|
||||
{
|
||||
this.sessionKey = sessionKey;
|
||||
this.cipher_text = cipher_text;
|
||||
}
|
||||
|
||||
public byte[] getSecret()
|
||||
{
|
||||
byte[] clone = Arrays.clone(sessionKey);
|
||||
|
||||
checkDestroyed();
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
public byte[] getEncapsulation()
|
||||
{
|
||||
byte[] clone = Arrays.clone(cipher_text);
|
||||
|
||||
checkDestroyed();
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
public void destroy()
|
||||
throws DestroyFailedException
|
||||
{
|
||||
if (!hasBeenDestroyed.getAndSet(true))
|
||||
{
|
||||
Arrays.clear(sessionKey);
|
||||
Arrays.clear(cipher_text);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isDestroyed()
|
||||
{
|
||||
return hasBeenDestroyed.get();
|
||||
}
|
||||
|
||||
void checkDestroyed()
|
||||
{
|
||||
if (isDestroyed())
|
||||
{
|
||||
throw new IllegalStateException("data has been destroyed");
|
||||
}
|
||||
}
|
||||
}
|
27
router/java/src/org/bouncycastle/util/Memoable.java
Normal file
27
router/java/src/org/bouncycastle/util/Memoable.java
Normal file
@ -0,0 +1,27 @@
|
||||
package org.bouncycastle.util;
|
||||
|
||||
/**
|
||||
* Interface for Memoable objects. Memoable objects allow the taking of a snapshot of their internal state
|
||||
* via the copy() method and then resetting the object back to that state later using the reset() method.
|
||||
*/
|
||||
public interface Memoable
|
||||
{
|
||||
/**
|
||||
* Produce a copy of this object with its configuration and in its current state.
|
||||
* <p>
|
||||
* The returned object may be used simply to store the state, or may be used as a similar object
|
||||
* starting from the copied state.
|
||||
*/
|
||||
Memoable copy();
|
||||
|
||||
/**
|
||||
* Restore a copied object state into this object.
|
||||
* <p>
|
||||
* Implementations of this method <em>should</em> try to avoid or minimise memory allocation to perform the reset.
|
||||
*
|
||||
* @param other an object originally {@link #copy() copied} from an object of the same type as this instance.
|
||||
* @throws ClassCastException if the provided object is not of the correct type.
|
||||
* @throws MemoableResetException if the <b>other</b> parameter is in some other way invalid.
|
||||
*/
|
||||
void reset(Memoable other);
|
||||
}
|
419
router/java/src/org/bouncycastle/util/Pack.java
Normal file
419
router/java/src/org/bouncycastle/util/Pack.java
Normal file
@ -0,0 +1,419 @@
|
||||
package org.bouncycastle.util;
|
||||
|
||||
/**
|
||||
* Utility methods for converting byte arrays into ints and longs, and back again.
|
||||
*/
|
||||
public abstract class Pack
|
||||
{
|
||||
public static short bigEndianToShort(byte[] bs, int off)
|
||||
{
|
||||
int n = (bs[off] & 0xff) << 8;
|
||||
n |= (bs[++off] & 0xff);
|
||||
return (short)n;
|
||||
}
|
||||
|
||||
public static int bigEndianToInt(byte[] bs, int off)
|
||||
{
|
||||
int n = bs[off] << 24;
|
||||
n |= (bs[++off] & 0xff) << 16;
|
||||
n |= (bs[++off] & 0xff) << 8;
|
||||
n |= (bs[++off] & 0xff);
|
||||
return n;
|
||||
}
|
||||
|
||||
public static void bigEndianToInt(byte[] bs, int off, int[] ns)
|
||||
{
|
||||
for (int i = 0; i < ns.length; ++i)
|
||||
{
|
||||
ns[i] = bigEndianToInt(bs, off);
|
||||
off += 4;
|
||||
}
|
||||
}
|
||||
|
||||
public static void bigEndianToInt(byte[] bs, int off, int[] ns, int nsOff, int nsLen)
|
||||
{
|
||||
for (int i = 0; i < nsLen; ++i)
|
||||
{
|
||||
ns[nsOff + i] = bigEndianToInt(bs, off);
|
||||
off += 4;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] intToBigEndian(int n)
|
||||
{
|
||||
byte[] bs = new byte[4];
|
||||
intToBigEndian(n, bs, 0);
|
||||
return bs;
|
||||
}
|
||||
|
||||
public static void intToBigEndian(int n, byte[] bs, int off)
|
||||
{
|
||||
bs[off] = (byte)(n >>> 24);
|
||||
bs[++off] = (byte)(n >>> 16);
|
||||
bs[++off] = (byte)(n >>> 8);
|
||||
bs[++off] = (byte)(n);
|
||||
}
|
||||
|
||||
public static byte[] intToBigEndian(int[] ns)
|
||||
{
|
||||
byte[] bs = new byte[4 * ns.length];
|
||||
intToBigEndian(ns, bs, 0);
|
||||
return bs;
|
||||
}
|
||||
|
||||
public static void intToBigEndian(int[] ns, byte[] bs, int off)
|
||||
{
|
||||
for (int i = 0; i < ns.length; ++i)
|
||||
{
|
||||
intToBigEndian(ns[i], bs, off);
|
||||
off += 4;
|
||||
}
|
||||
}
|
||||
|
||||
public static void intToBigEndian(int[] ns, int nsOff, int nsLen, byte[] bs, int bsOff)
|
||||
{
|
||||
for (int i = 0; i < nsLen; ++i)
|
||||
{
|
||||
intToBigEndian(ns[nsOff + i], bs, bsOff);
|
||||
bsOff += 4;
|
||||
}
|
||||
}
|
||||
|
||||
public static long bigEndianToLong(byte[] bs, int off)
|
||||
{
|
||||
int hi = bigEndianToInt(bs, off);
|
||||
int lo = bigEndianToInt(bs, off + 4);
|
||||
return ((long)(hi & 0xffffffffL) << 32) | (long)(lo & 0xffffffffL);
|
||||
}
|
||||
|
||||
public static void bigEndianToLong(byte[] bs, int off, long[] ns)
|
||||
{
|
||||
for (int i = 0; i < ns.length; ++i)
|
||||
{
|
||||
ns[i] = bigEndianToLong(bs, off);
|
||||
off += 8;
|
||||
}
|
||||
}
|
||||
|
||||
public static void bigEndianToLong(byte[] bs, int bsOff, long[] ns, int nsOff, int nsLen)
|
||||
{
|
||||
for (int i = 0; i < nsLen; ++i)
|
||||
{
|
||||
ns[nsOff + i] = bigEndianToLong(bs, bsOff);
|
||||
bsOff += 8;
|
||||
}
|
||||
}
|
||||
|
||||
public static long bigEndianToLong(byte[] bs, int off, int len)
|
||||
{
|
||||
long x = 0;
|
||||
for (int i = 0; i < len; ++i)
|
||||
{
|
||||
x |= (bs[i + off] & 0xFFL) << ((7 - i) << 3);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
public static byte[] longToBigEndian(long n)
|
||||
{
|
||||
byte[] bs = new byte[8];
|
||||
longToBigEndian(n, bs, 0);
|
||||
return bs;
|
||||
}
|
||||
|
||||
public static void longToBigEndian(long n, byte[] bs, int off)
|
||||
{
|
||||
intToBigEndian((int)(n >>> 32), bs, off);
|
||||
intToBigEndian((int)(n & 0xffffffffL), bs, off + 4);
|
||||
}
|
||||
|
||||
public static byte[] longToBigEndian(long[] ns)
|
||||
{
|
||||
byte[] bs = new byte[8 * ns.length];
|
||||
longToBigEndian(ns, bs, 0);
|
||||
return bs;
|
||||
}
|
||||
|
||||
public static void longToBigEndian(long[] ns, byte[] bs, int off)
|
||||
{
|
||||
for (int i = 0; i < ns.length; ++i)
|
||||
{
|
||||
longToBigEndian(ns[i], bs, off);
|
||||
off += 8;
|
||||
}
|
||||
}
|
||||
|
||||
public static void longToBigEndian(long[] ns, int nsOff, int nsLen, byte[] bs, int bsOff)
|
||||
{
|
||||
for (int i = 0; i < nsLen; ++i)
|
||||
{
|
||||
longToBigEndian(ns[nsOff + i], bs, bsOff);
|
||||
bsOff += 8;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value The number
|
||||
* @param bs The target.
|
||||
* @param off Position in target to start.
|
||||
* @param bytes number of bytes to write.
|
||||
* @deprecated Will be removed
|
||||
*/
|
||||
public static void longToBigEndian(long value, byte[] bs, int off, int bytes)
|
||||
{
|
||||
for (int i = bytes - 1; i >= 0; i--)
|
||||
{
|
||||
bs[i + off] = (byte)(value & 0xff);
|
||||
value >>>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
public static short littleEndianToShort(byte[] bs, int off)
|
||||
{
|
||||
int n = bs[off] & 0xff;
|
||||
n |= (bs[++off] & 0xff) << 8;
|
||||
return (short)n;
|
||||
}
|
||||
|
||||
public static int littleEndianToInt(byte[] bs, int off)
|
||||
{
|
||||
int n = bs[off] & 0xff;
|
||||
n |= (bs[++off] & 0xff) << 8;
|
||||
n |= (bs[++off] & 0xff) << 16;
|
||||
n |= bs[++off] << 24;
|
||||
return n;
|
||||
}
|
||||
|
||||
public static int littleEndianToInt_High(byte[] bs, int off, int len)
|
||||
{
|
||||
return littleEndianToInt_Low(bs, off, len) << ((4 - len) << 3);
|
||||
}
|
||||
|
||||
public static int littleEndianToInt_Low(byte[] bs, int off, int len)
|
||||
{
|
||||
// assert 1 <= len && len <= 4;
|
||||
|
||||
int result = bs[off] & 0xff;
|
||||
int pos = 0;
|
||||
for (int i = 1; i < len; ++i)
|
||||
{
|
||||
pos += 8;
|
||||
result |= (bs[off + i] & 0xff) << pos;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void littleEndianToInt(byte[] bs, int off, int[] ns)
|
||||
{
|
||||
for (int i = 0; i < ns.length; ++i)
|
||||
{
|
||||
ns[i] = littleEndianToInt(bs, off);
|
||||
off += 4;
|
||||
}
|
||||
}
|
||||
|
||||
public static void littleEndianToInt(byte[] bs, int bOff, int[] ns, int nOff, int count)
|
||||
{
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
ns[nOff + i] = littleEndianToInt(bs, bOff);
|
||||
bOff += 4;
|
||||
}
|
||||
}
|
||||
|
||||
public static int[] littleEndianToInt(byte[] bs, int off, int count)
|
||||
{
|
||||
int[] ns = new int[count];
|
||||
for (int i = 0; i < ns.length; ++i)
|
||||
{
|
||||
ns[i] = littleEndianToInt(bs, off);
|
||||
off += 4;
|
||||
}
|
||||
return ns;
|
||||
}
|
||||
|
||||
public static byte[] shortToLittleEndian(short n)
|
||||
{
|
||||
byte[] bs = new byte[2];
|
||||
shortToLittleEndian(n, bs, 0);
|
||||
return bs;
|
||||
}
|
||||
|
||||
public static void shortToLittleEndian(short n, byte[] bs, int off)
|
||||
{
|
||||
bs[off] = (byte)(n);
|
||||
bs[++off] = (byte)(n >>> 8);
|
||||
}
|
||||
|
||||
|
||||
public static byte[] shortToBigEndian(short n)
|
||||
{
|
||||
byte[] r = new byte[2];
|
||||
shortToBigEndian(n, r, 0);
|
||||
return r;
|
||||
}
|
||||
|
||||
public static void shortToBigEndian(short n, byte[] bs, int off)
|
||||
{
|
||||
bs[off] = (byte)(n >>> 8);
|
||||
bs[++off] = (byte)(n);
|
||||
}
|
||||
|
||||
|
||||
public static byte[] intToLittleEndian(int n)
|
||||
{
|
||||
byte[] bs = new byte[4];
|
||||
intToLittleEndian(n, bs, 0);
|
||||
return bs;
|
||||
}
|
||||
|
||||
public static void intToLittleEndian(int n, byte[] bs, int off)
|
||||
{
|
||||
bs[off] = (byte)(n);
|
||||
bs[++off] = (byte)(n >>> 8);
|
||||
bs[++off] = (byte)(n >>> 16);
|
||||
bs[++off] = (byte)(n >>> 24);
|
||||
}
|
||||
|
||||
public static byte[] intToLittleEndian(int[] ns)
|
||||
{
|
||||
byte[] bs = new byte[4 * ns.length];
|
||||
intToLittleEndian(ns, bs, 0);
|
||||
return bs;
|
||||
}
|
||||
|
||||
public static void intToLittleEndian(int[] ns, byte[] bs, int off)
|
||||
{
|
||||
for (int i = 0; i < ns.length; ++i)
|
||||
{
|
||||
intToLittleEndian(ns[i], bs, off);
|
||||
off += 4;
|
||||
}
|
||||
}
|
||||
|
||||
public static void intToLittleEndian(int[] ns, int nsOff, int nsLen, byte[] bs, int bsOff)
|
||||
{
|
||||
for (int i = 0; i < nsLen; ++i)
|
||||
{
|
||||
intToLittleEndian(ns[nsOff + i], bs, bsOff);
|
||||
bsOff += 4;
|
||||
}
|
||||
}
|
||||
|
||||
public static long littleEndianToLong(byte[] bs, int off)
|
||||
{
|
||||
int lo = littleEndianToInt(bs, off);
|
||||
int hi = littleEndianToInt(bs, off + 4);
|
||||
return ((long)(hi & 0xffffffffL) << 32) | (long)(lo & 0xffffffffL);
|
||||
}
|
||||
|
||||
public static void littleEndianToLong(byte[] bs, int off, long[] ns)
|
||||
{
|
||||
for (int i = 0; i < ns.length; ++i)
|
||||
{
|
||||
ns[i] = littleEndianToLong(bs, off);
|
||||
off += 8;
|
||||
}
|
||||
}
|
||||
|
||||
public static long littleEndianToLong(byte[] input, int off, int len)
|
||||
{
|
||||
long result = 0;
|
||||
for (int i = 0; i < len; ++i)
|
||||
{
|
||||
result |= (input[off + i] & 0xFFL) << (i << 3);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void littleEndianToLong(byte[] bs, int bsOff, long[] ns, int nsOff, int nsLen)
|
||||
{
|
||||
for (int i = 0; i < nsLen; ++i)
|
||||
{
|
||||
ns[nsOff + i] = littleEndianToLong(bs, bsOff);
|
||||
bsOff += 8;
|
||||
}
|
||||
}
|
||||
|
||||
public static void longToLittleEndian_High(long n, byte[] bs, int off, int len)
|
||||
{
|
||||
//Debug.Assert(1 <= len && len <= 8);
|
||||
int pos = 56;
|
||||
bs[off] = (byte)(n >>> pos);
|
||||
for (int i = 1; i < len; ++i)
|
||||
{
|
||||
pos -= 8;
|
||||
bs[off + i] = (byte)(n >>> pos);
|
||||
}
|
||||
}
|
||||
|
||||
public static void longToLittleEndian(long n, byte[] bs, int off, int len)
|
||||
{
|
||||
for (int i = 0; i < len; ++i)
|
||||
{
|
||||
bs[off + i] = (byte)(n >>> (i << 3));
|
||||
}
|
||||
}
|
||||
|
||||
// public static void longToLittleEndian_Low(long n, byte[] bs, int off, int len)
|
||||
// {
|
||||
// longToLittleEndian_High(n << ((8 - len) << 3), bs, off, len);
|
||||
// }
|
||||
|
||||
public static long littleEndianToLong_High(byte[] bs, int off, int len)
|
||||
{
|
||||
return littleEndianToLong_Low(bs, off, len) << ((8 - len) << 3);
|
||||
}
|
||||
|
||||
public static long littleEndianToLong_Low(byte[] bs, int off, int len)
|
||||
{
|
||||
//Debug.Assert(1 <= len && len <= 8);
|
||||
long result = bs[off] & 0xFF;
|
||||
for (int i = 1; i < len; ++i)
|
||||
{
|
||||
result <<= 8;
|
||||
result |= bs[off + i] & 0xFF;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static byte[] longToLittleEndian(long n)
|
||||
{
|
||||
byte[] bs = new byte[8];
|
||||
longToLittleEndian(n, bs, 0);
|
||||
return bs;
|
||||
}
|
||||
|
||||
public static void longToLittleEndian(long n, byte[] bs, int off)
|
||||
{
|
||||
intToLittleEndian((int)(n & 0xffffffffL), bs, off);
|
||||
intToLittleEndian((int)(n >>> 32), bs, off + 4);
|
||||
}
|
||||
|
||||
public static byte[] longToLittleEndian(long[] ns)
|
||||
{
|
||||
byte[] bs = new byte[8 * ns.length];
|
||||
longToLittleEndian(ns, bs, 0);
|
||||
return bs;
|
||||
}
|
||||
|
||||
public static void longToLittleEndian(long[] ns, byte[] bs, int off)
|
||||
{
|
||||
for (int i = 0; i < ns.length; ++i)
|
||||
{
|
||||
longToLittleEndian(ns[i], bs, off);
|
||||
off += 8;
|
||||
}
|
||||
}
|
||||
|
||||
public static void longToLittleEndian(long[] ns, int nsOff, int nsLen, byte[] bs, int bsOff)
|
||||
{
|
||||
for (int i = 0; i < nsLen; ++i)
|
||||
{
|
||||
longToLittleEndian(ns[nsOff + i], bs, bsOff);
|
||||
bsOff += 8;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
4
router/java/src/org/bouncycastle/util/package-info.java
Normal file
4
router/java/src/org/bouncycastle/util/package-info.java
Normal file
@ -0,0 +1,4 @@
|
||||
/**
|
||||
* General purpose utility classes used throughout the APIs.
|
||||
*/
|
||||
package org.bouncycastle.util;
|
Reference in New Issue
Block a user