com.joyent.http.signature.crypto.MantaNativeRSACoreEngine Maven / Gradle / Ivy
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.joyent.http.signature.crypto;
import com.squareup.jnagmp.GmpInteger;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.crypto.params.RSAKeyParameters;
import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
import java.math.BigInteger;
import static com.squareup.jnagmp.Gmp.modPowInsecure;
import static com.squareup.jnagmp.Gmp.modPowSecure;
/**
* Class copied wholesale from the com.squareup.crypto.rsa project that uses
* native libgmp to improve RSA performance. The only modifications to this
* class are formatting and style.
*/
public class MantaNativeRSACoreEngine {
private RSAKeyParameters key;
private boolean forEncryption;
private boolean isPrivate;
private boolean isSmallExponent;
// cached components for private CRT key
private GmpInteger p;
private GmpInteger q;
private GmpInteger dP;
private GmpInteger dQ;
private BigInteger qInv;
// cached components for public key
private GmpInteger exponent;
private GmpInteger modulus;
/**
* initialise the RSA engine.
*
* @param forEncryption true if we are encrypting, false otherwise.
* @param param the necessary RSA key parameters.
*/
public void init(
boolean forEncryption,
CipherParameters param) {
if (param instanceof ParametersWithRandom) {
ParametersWithRandom rParam = (ParametersWithRandom) param;
key = (RSAKeyParameters) rParam.getParameters();
} else {
key = (RSAKeyParameters) param;
}
this.forEncryption = forEncryption;
if (key instanceof RSAPrivateCrtKeyParameters) {
isPrivate = true;
//
// we have the extra factors, use the Chinese Remainder Theorem - the author
// wishes to express his thanks to Dirk Bonekaemper at rtsffm.com for
// advice regarding the expression of this.
//
RSAPrivateCrtKeyParameters crtKey = (RSAPrivateCrtKeyParameters) key;
p = new GmpInteger(crtKey.getP());
q = new GmpInteger(crtKey.getQ());
dP = new GmpInteger(crtKey.getDP());
dQ = new GmpInteger(crtKey.getDQ());
qInv = crtKey.getQInv();
exponent = modulus = null;
} else {
isPrivate = false;
exponent = new GmpInteger(key.getExponent());
modulus = new GmpInteger(key.getModulus());
isSmallExponent = exponent.bitLength() < 64;
p = q = dP = dQ = null;
qInv = null;
}
}
/**
* Return the maximum size for an input block to this engine.
* For RSA this is always one byte less than the key size on
* encryption, and the same length as the key size on decryption.
*
* @return maximum size for an input block.
*/
public int getInputBlockSize() {
int bitSize = key.getModulus().bitLength();
if (forEncryption) {
return (bitSize + 7) / 8 - 1;
} else {
return (bitSize + 7) / 8;
}
}
/**
* Return the maximum size for an output block to this engine.
* For RSA this is always one byte less than the key size on
* decryption, and the same length as the key size on encryption.
*
* @return maximum size for an output block.
*/
public int getOutputBlockSize() {
int bitSize = key.getModulus().bitLength();
if (forEncryption) {
return (bitSize + 7) / 8;
} else {
return (bitSize + 7) / 8 - 1;
}
}
public BigInteger convertInput(
byte[] in,
int inOff,
int inLen) {
if (inLen > (getInputBlockSize() + 1)) {
throw new DataLengthException("input too large for RSA cipher.");
} else if (inLen == (getInputBlockSize() + 1) && !forEncryption) {
throw new DataLengthException("input too large for RSA cipher.");
}
byte[] block;
if (inOff != 0 || inLen != in.length) {
block = new byte[inLen];
System.arraycopy(in, inOff, block, 0, inLen);
} else {
block = in;
}
BigInteger res = new BigInteger(1, block);
if (res.compareTo(key.getModulus()) >= 0) {
throw new DataLengthException("input too large for RSA cipher.");
}
return res;
}
public byte[] convertOutput(
BigInteger result) {
byte[] output = result.toByteArray();
if (forEncryption) {
if (output[0] == 0 && output.length > getOutputBlockSize()) // have ended up with an extra zero byte, copy down.
{
byte[] tmp = new byte[output.length - 1];
System.arraycopy(output, 1, tmp, 0, tmp.length);
return tmp;
}
if (output.length < getOutputBlockSize()) // have ended up with less bytes than normal, lengthen
{
byte[] tmp = new byte[getOutputBlockSize()];
System.arraycopy(output, 0, tmp, tmp.length - output.length, output.length);
return tmp;
}
} else {
if (output[0] == 0) // have ended up with an extra zero byte, copy down.
{
byte[] tmp = new byte[output.length - 1];
System.arraycopy(output, 1, tmp, 0, tmp.length);
return tmp;
}
}
return output;
}
public BigInteger processBlock(BigInteger input) {
if (isPrivate) {
BigInteger mP, mQ, h, m;
// mP = ((input mod p) ^ dP)) mod p
mP = modPowSecure(input.remainder(p), dP, p);
// mQ = ((input mod q) ^ dQ)) mod q
mQ = modPowSecure(input.remainder(q), dQ, q);
// h = qInv * (mP - mQ) mod p
h = mP.subtract(mQ);
h = h.multiply(qInv);
h = h.mod(p); // mod (in Java) returns the positive residual
// m = h * q + mQ
m = h.multiply(q);
m = m.add(mQ);
return m;
} else {
if (isSmallExponent) {
// Public key with reasonable (small) exponent, no need for secure.
return modPowInsecure(input, exponent, modulus);
} else {
// Client mistakenly configured private key as public? Better be safe than sorry.
return modPowSecure(input, exponent, modulus);
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy