All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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