package org.freertr.cry; import org.freertr.enc.encAsn1; import java.math.BigInteger; import org.freertr.pack.packHolder; import org.freertr.pack.packSsh; import org.freertr.util.bits; /** * rivest shamir adleman * * @author matecsaba */ public class cryKeyRSA extends cryKeyGeneric { /** * create instance */ public cryKeyRSA() { } /** * ssh name */ public final static String sshName = "ssh-rsa"; /** * ssh name */ public final static String sshName2 = "rsa-sha2-256"; /** * ssh name */ public final static String sshName3 = "rsa-sha2-512"; /** * n modulus */ public BigInteger modulus; /** * e public exponent */ public BigInteger pubExp; /** * d private exponent */ protected BigInteger privExp; /** * p prime1 exponent */ protected BigInteger prime1; /** * q prime2 exponent */ protected BigInteger prime2; /** * dmp exponent1 */ protected BigInteger expon1; /** * dmq exponent2 */ protected BigInteger expon2; /** * iqp coefficient */ protected BigInteger coeff; public String toString() { return "mod=" + modulus + " pubExp=" + pubExp + " privExp=" + privExp + " p1=" + prime1 + " p2=" + prime2 + " e1=" + expon1 + " e2=" + expon2 + " coeff=" + coeff; } public String algName() { return "rsa"; } public boolean certReader(packHolder pck) { encAsn1 a = new encAsn1(); if (a.tagRead(pck)) { return true; } if ((!a.cnst) || (a.tag != encAsn1.tagSequence)) { return true; } pck = a.getPack(); if (a.tagRead(pck)) { return true; } if ((!a.cnst) || (a.tag != encAsn1.tagSequence)) { return true; } packHolder p = a.getPack(); if (a.tagRead(p)) { return true; } if (cryCertificate.objid2int(a) != cryCertificate.typRsaEncrypt) { return true; } if (a.tagRead(pck)) { return true; } if ((a.cnst) || (a.tag != encAsn1.tagBitString)) { return true; } pck = a.getPack(); pck.getSkip(1); if (a.tagRead(pck)) { return true; } if ((!a.cnst) || (a.tag != encAsn1.tagSequence)) { return true; } pck = a.getPack(); modulus = encAsn1.readBigInt(pck); pubExp = encAsn1.readBigInt(pck); return false; } public void certWriter(packHolder pck) { packHolder p1 = new packHolder(true, true); packHolder p2 = new packHolder(true, true); packHolder p3 = new packHolder(true, true); encAsn1.writeObjectId(p1, cryCertificate.oidRsaEncrypt); encAsn1.writeNull(p1); encAsn1.writeSequence(p2, p1); encAsn1.writeBigInt(p3, modulus); encAsn1.writeBigInt(p3, pubExp); p1.clear(); encAsn1.writeSequence(p1, p3); p1.putByte(0, 0); p1.putSkip(1); p1.merge2beg(); encAsn1.writeBitString(p2, p1); encAsn1.writeSequence(pck, p2); } public boolean privReader(packHolder pck) { encAsn1 a = new encAsn1(); if (a.tagRead(pck)) { return true; } if ((!a.cnst) || (a.tag != encAsn1.tagSequence)) { return true; } pck = a.getPack(); BigInteger ver = encAsn1.readBigInt(pck); if (ver == null) { return true; } modulus = encAsn1.readBigInt(pck); if (modulus == null) { return true; } pubExp = encAsn1.readBigInt(pck); if (pubExp == null) { return true; } privExp = encAsn1.readBigInt(pck); if (privExp == null) { return true; } prime1 = encAsn1.readBigInt(pck); if (prime1 == null) { return true; } prime2 = encAsn1.readBigInt(pck); if (prime2 == null) { return true; } expon1 = encAsn1.readBigInt(pck); if (expon1 == null) { return true; } expon2 = encAsn1.readBigInt(pck); if (expon2 == null) { return true; } coeff = encAsn1.readBigInt(pck); if (coeff == null) { return true; } if (pck.dataSize() != 0) { return true; } return false; } public void privWriter(packHolder pck) { packHolder p = new packHolder(true, true); encAsn1.writeBigInt(p, BigInteger.ZERO); encAsn1.writeBigInt(p, modulus); encAsn1.writeBigInt(p, pubExp); encAsn1.writeBigInt(p, privExp); encAsn1.writeBigInt(p, prime1); encAsn1.writeBigInt(p, prime2); encAsn1.writeBigInt(p, expon1); encAsn1.writeBigInt(p, expon2); encAsn1.writeBigInt(p, coeff); encAsn1.writeSequence(pck, p); } public boolean keyMake(String nam) { return false; } public boolean keyMake(int len) { pubExp = new BigInteger("65537", 10); prime1 = randomPrime(len / 2); prime2 = randomPrime(len / 2); if (prime1.compareTo(prime2) < 0) { BigInteger i = prime1; prime1 = prime2; prime2 = i; } modulus = prime1.multiply(prime2); BigInteger i1 = prime1.subtract(BigInteger.ONE); BigInteger i2 = prime2.subtract(BigInteger.ONE); BigInteger i0 = i1.multiply(i2); try { privExp = pubExp.modInverse(i0); } catch (Exception e) { return true; } expon1 = privExp.mod(i1); expon2 = privExp.mod(i2); try { coeff = prime2.modInverse(prime1); } catch (Exception e) { return true; } return false; } public boolean keyVerify() { if (!testPrime(pubExp)) { return true; } if (!testPrime(prime1)) { return true; } if (!testPrime(prime2)) { return true; } if (prime1.compareTo(prime2) < 0) { return true; } if (modulus.compareTo(prime1.multiply(prime2)) != 0) { return true; } BigInteger i1 = prime1.subtract(BigInteger.ONE); BigInteger i2 = prime2.subtract(BigInteger.ONE); BigInteger i0 = i1.multiply(i2); if (privExp.compareTo(pubExp.modInverse(i0)) != 0) { return true; } if (expon1.compareTo(privExp.mod(i1)) != 0) { return true; } if (expon2.compareTo(privExp.mod(i2)) != 0) { return true; } if (coeff.compareTo(prime2.modInverse(prime1)) != 0) { return true; } return false; } public int keySize() { return modulus.bitLength(); } /** * do encryption * * @param src cleartext * @return ciphertext */ public byte[] doEncrypt(byte[] src) { BigInteger i = buffer2bigInt(src, 0, src.length); i = i.modPow(pubExp, modulus); return i.toByteArray(); } /** * do decryption * * @param src ciphertext * @return cleartext */ public byte[] doDecrypt(byte[] src) { BigInteger i = buffer2bigInt(src, 0, src.length); i = i.modPow(privExp, modulus); return i.toByteArray(); } public boolean sshReader(byte[] key) { packHolder p = new packHolder(true, true); p.putCopy(key, 0, 0, key.length); p.putSkip(key.length); p.merge2beg(); if (!packSsh.stringRead(p).equals(sshName)) { return true; } pubExp = packSsh.bigIntRead(p); modulus = packSsh.bigIntRead(p); return false; } public byte[] sshWriter() { packHolder p = new packHolder(true, true); packSsh.stringWrite(p, sshName); packSsh.bigIntWrite(p, pubExp); packSsh.bigIntWrite(p, modulus); p.merge2beg(); return p.getCopy(); } /** * mask generator function 1 * * @param hsh hash * @param src source * @param ofs offset * @param len length * @param need needed * @return mask */ public byte[] pssMgf1(cryHashGeneric hsh, byte[] src, int ofs, int len, int need) { int hl = hsh.getHashSize(); byte[] res = new byte[need]; byte[] buf = new byte[4]; int cnt = 0; for (; cnt < (need / hl); cnt++) { bits.msbPutD(buf, 0, cnt); hsh.init(); hsh.update(src, ofs, len); hsh.update(buf, 0, buf.length); bits.byteCopy(hsh.finish(), 0, res, cnt * hl, hl); } if ((cnt * hl) >= need) { return res; } bits.msbPutD(buf, 0, cnt); hsh.init(); hsh.update(src, ofs, len); hsh.update(buf, 0, buf.length); bits.byteCopy(hsh.finish(), 0, res, cnt * hl, res.length - (cnt * hl)); return res; } /** * pad for tls12 * * @param oid oid bytes * @param src buffer to pad * @return padded integer */ public BigInteger PKCS1t2pad(byte[] oid, byte[] src) { byte[] buf = new byte[(modulus.bitLength() + 7) / 8]; for (int i = 0; i < buf.length; i++) { buf[i] = (byte) 0xff; } buf[0] = 0; buf[1] = 1; bits.byteCopy(src, 0, buf, buf.length - src.length, src.length); bits.byteCopy(oid, 0, buf, buf.length - src.length - oid.length, oid.length); return new BigInteger(buf); } /** * pad for tls11 * * @param src buffer to pad * @return padded integer */ public BigInteger PKCS1t1pad(byte[] src) { byte[] buf = new byte[(modulus.bitLength() + 7) / 8]; for (int i = 0; i < buf.length; i++) { buf[i] = (byte) 0xff; } buf[0] = 0; buf[1] = 1; bits.byteCopy(src, 0, buf, buf.length - src.length, src.length); buf[buf.length - src.length - 1] = 0; return new BigInteger(buf); } /** * pad for pkcs15 * * @param src buffer to pad * @return padded buffer */ public byte[] PKCS1t15pad(byte[] src) { byte[] buf = new byte[(modulus.bitLength() + 7) / 8]; buf[1] = 2; for (int i = 2; i < buf.length - src.length; i++) { int o; for (;;) { o = bits.randomB(); if (o != 0) { break; } } buf[i] = (byte) o; } buf[buf.length - src.length - 1] = 0; bits.byteCopy(src, 0, buf, buf.length - src.length, src.length); return buf; } /** * unpad for pkcs15 * * @param src buffer to unpad * @return unpadded buffer */ public byte[] PKCS1t15unpad(byte[] src) { int o = -1; for (int i = src.length - 1; i >= 0; i--) { if (src[i] == 0) { o = i; } } if (o < 0) { return src; } byte[] buf = new byte[src.length - o - 1]; for (int i = 0; i < buf.length; i++) { buf[i] = src[src.length - buf.length + i]; } return buf; } public boolean sshVerify(cryHashGeneric algo, String algn, byte[] hash, byte[] sign) { hash = cryHashGeneric.compute(algo, hash); packHolder p = new packHolder(true, true); p.putCopy(sign, 0, 0, sign.length); p.putSkip(sign.length); p.merge2beg(); if (!packSsh.stringRead(p).equals(algn)) { return true; } BigInteger s = packSsh.bigUIntRead(p); s = s.modPow(pubExp, modulus); return PKCS1t2pad(algo.getPkcs(), hash).compareTo(s) != 0; } public byte[] sshSigning(cryHashGeneric algo, String algn, byte[] hash) { hash = cryHashGeneric.compute(algo, hash); packHolder p = new packHolder(true, true); BigInteger s = PKCS1t2pad(algo.getPkcs(), hash); s = s.modPow(privExp, modulus); packSsh.stringWrite(p, algn); packSsh.bigUIntWrite(p, s); p.merge2beg(); return p.getCopy(); } public boolean certVerify(cryHashGeneric pkcs, byte[] hash, byte[] sign) { BigInteger s = cryUtils.buf2bigUint(sign); s = s.modPow(pubExp, modulus); return PKCS1t2pad(pkcs.getPkcs(), hash).compareTo(s) != 0; } public byte[] certSigning(cryHashGeneric pkcs, byte[] hash) { BigInteger s = PKCS1t2pad(pkcs.getPkcs(), hash); s = s.modPow(privExp, modulus); return s.toByteArray(); } /** * do padding * * @param ver version * @param pkcs hash algorithm * @param hash hash hash to pad * @return padded, null if pss */ public BigInteger doPadding(int ver, cryHashGeneric pkcs, byte[] hash) { if (ver < 0x100) { return PKCS1t1pad(hash); } if (ver < 0x800) { return PKCS1t2pad(pkcs.getPkcs(), hash); } return null; } public boolean tlsVerify(int ver, cryHashGeneric pkcs, byte[] hash, byte[] sign) { BigInteger s = cryUtils.buf2bigUint(sign); s = s.modPow(pubExp, modulus); BigInteger h = doPadding(ver, pkcs, hash); if (h != null) { return h.compareTo(s) != 0; } byte[] sgn = s.toByteArray(); if (sgn.length < (hash.length + hash.length + 2)) { return true; } byte[] buf = new byte[hash.length + hash.length + 8]; bits.byteCopy(hash, 0, buf, 8, hash.length); int embt = modulus.bitLength() - 1; byte[] blk = new byte[(embt + 7) / 8]; bits.byteCopy(sgn, 0, blk, blk.length - sgn.length, sgn.length); int fbm = 0xff >>> ((blk.length * 8) - embt); if ((blk[0] & 0xff) != (blk[0] & fbm)) { return true; } if ((blk[blk.length - 1] & 0xff) != 0xbc) { return true; } byte[] dbm = pssMgf1(pkcs, blk, blk.length - hash.length - 1, hash.length, blk.length - hash.length - 1); for (int i = 0; i != dbm.length; i++) { blk[i] ^= dbm[i]; } blk[0] &= (byte) fbm; for (int i = 0; i != blk.length - hash.length - hash.length - 2; i++) { if (blk[i] != 0) { return true; } } if (blk[blk.length - hash.length - hash.length - 2] != 0x01) { return true; } bits.byteCopy(blk, blk.length - hash.length - hash.length - 1, buf, buf.length - hash.length, hash.length); pkcs.init(); pkcs.update(buf); bits.byteCopy(pkcs.finish(), 0, buf, buf.length - hash.length, hash.length); return bits.byteComp(blk, blk.length - hash.length - 1, buf, buf.length - hash.length, hash.length) != 0; } public byte[] tlsSigning(int ver, cryHashGeneric pkcs, byte[] hash) { BigInteger s = doPadding(ver, pkcs, hash); if (s != null) { s = s.modPow(privExp, modulus); return cryUtils.bigUint2buf(s); } byte[] salt = new byte[hash.length]; for (int i = 0; i < salt.length; i++) { salt[i] = (byte) bits.randomB(); } byte[] buf = new byte[hash.length + hash.length + 8]; bits.byteCopy(hash, 0, buf, 8, hash.length); bits.byteCopy(salt, 0, buf, buf.length - hash.length, hash.length); pkcs.init(); pkcs.update(buf); byte[] h = pkcs.finish(); int embt = modulus.bitLength() - 1; byte[] blk = new byte[(embt + 7) / 8]; blk[blk.length - hash.length - hash.length - 2] = 0x01; bits.byteCopy(salt, 0, blk, blk.length - hash.length - hash.length - 1, hash.length); byte[] dbm = pssMgf1(pkcs, h, 0, h.length, blk.length - hash.length - 1); for (int i = 0; i != dbm.length; i++) { blk[i] ^= dbm[i]; } bits.byteCopy(h, 0, blk, blk.length - hash.length - 1, hash.length); blk[0] &= (byte) (0xff >>> ((blk.length * 8) - embt)); blk[blk.length - 1] = (byte) 0xbc; s = new BigInteger(blk); s = s.modPow(privExp, modulus); return cryUtils.bigUint2buf(s); } }