org.kapott.cryptalgs.ISO9796p1 Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hbci4j-core Show documentation
Show all versions of hbci4j-core Show documentation
HBCI4j - Home Banking Computer Interface for Java
/**********************************************************************
*
* This file is part of HBCI4Java.
* Copyright (c) 2001-2010 Stefan Palme
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
**********************************************************************/
package org.kapott.cryptalgs;
import java.math.BigInteger;
import java.security.InvalidAlgorithmParameterException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SignatureException;
import java.security.SignatureSpi;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.AlgorithmParameterSpec;
import java.util.Arrays;
import java.util.logging.Logger;
public class ISO9796p1
extends SignatureSpi
{
private RSAPublicKey pubKey;
private PrivateKey privKey;
private MessageDigest dig;
private SignatureParamSpec param;
protected Logger getLogger()
{
return Logger.getLogger(this.getClass().getName());
}
@Override @Deprecated
protected Object engineGetParameter(String parameter)
{
return null;
}
@Override
protected void engineInitSign(PrivateKey privateKey)
{
try {
this.dig=MessageDigest.getInstance(this.param.getHashAlg(), this.param.getProvider());
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
} catch (NoSuchProviderException e) {
throw new RuntimeException(e);
}
this.privKey=privateKey;
}
@Override
protected void engineInitVerify(PublicKey publicKey)
{
try {
this.dig=MessageDigest.getInstance(this.param.getHashAlg(), this.param.getProvider());
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
} catch (NoSuchProviderException e) {
throw new RuntimeException(e);
}
this.pubKey=(RSAPublicKey)publicKey;
}
@Override @Deprecated
protected void engineSetParameter(String param1, Object value)
{
// do nothing
}
@Override
protected void engineSetParameter(AlgorithmParameterSpec param1)
throws InvalidAlgorithmParameterException
{
if (param1 instanceof SignatureParamSpec)
this.param=(SignatureParamSpec)(param1);
else {
throw new InvalidAlgorithmParameterException();
}
}
@Override
protected byte[] engineSign()
throws SignatureException
{
BigInteger bModulus;
if (this.privKey instanceof RSAPrivateKey) {
bModulus=((RSAPrivateKey)this.privKey).getModulus();
} else {
RSAPrivateCrtKey2 key2=(RSAPrivateCrtKey2)this.privKey;
bModulus=key2.getP().multiply(key2.getQ());
}
byte[] modulus=bModulus.toByteArray();
byte[] buffer=this.dig.digest();
byte[] rr=prepareForSig(buffer,bModulus);
byte[] is;
if (this.privKey instanceof RSAPrivateKey) {
getLogger().fine("signing with (n,d)-algorithm");
BigInteger bPrivExponent=((RSAPrivateKey)this.privKey).getPrivateExponent();
BigInteger bIS=(new BigInteger(+1,rr)).modPow(bPrivExponent,bModulus);
is=bIS.toByteArray();
} else {
getLogger().fine("signing with (p,q,dP,dQ,qInv)-algorithm");
RSAPrivateCrtKey2 key2=(RSAPrivateCrtKey2)this.privKey;
BigInteger p=key2.getP();
BigInteger q=key2.getQ();
BigInteger dP=key2.getdP();
BigInteger dQ=key2.getdQ();
BigInteger qInv=key2.getQInv();
BigInteger encData=new BigInteger(+1,rr);
BigInteger m1=encData.modPow(dP,p);
BigInteger m2=encData.modPow(dQ,q);
BigInteger h=m1.subtract(m2).multiply(qInv).mod(p);
is=m2.add(q.multiply(h)).toByteArray();
}
// adjust value
byte[] sig=getSigFromIS(is,modulus);
return sig;
}
public static byte[] prepareForSig(byte[] buffer,BigInteger bModulus)
throws SignatureException
{
/* padding; 'cause my buffer is already byte-aligned, there
are no padding bits to be prepended */
byte[] mp=new byte[buffer.length];
System.arraycopy(buffer,0,mp,0,buffer.length);
int k=bModulus.bitLength()-1;
int z=mp.length;
int r=1;
if (!((z<<4)<=(k+3))) {
throw new SignatureException("16*z is greater than k");
}
// extension (concatenate MP multiple times)
/*double t2=((double)(k))/8;
if ((k&0x07) != 0)
t2 += 1.0;
int t = ((int)(t2)) >> 1;*/
int t=(k-1)>>4;
if (((k-1)&0x0F)!=0)
t++;
byte[] me=getMEfromMP(mp, t);
/* creating redundancy by interleaving the extended message bytes
with redundancy bytes */
byte[] mr=getMRfromME(me,t,z,r);
// get intermediate integer
byte[] ir=getIRfromMR(mr,k);
// calculate signature
byte[] rr=ir; // getRRfromIR(ir, k, modulus, privExponent);
return rr;
}
@Override
protected int engineSign(byte[] output,int offset,int len)
throws SignatureException
{
byte[] sig=engineSign();
if (offset+len>output.length)
throw new SignatureException("output result too large for buffer");
System.arraycopy(sig,0,output,offset,sig.length);
return sig.length;
}
@Override
protected void engineUpdate(byte b)
{
this.dig.update(b);
}
@Override
protected void engineUpdate(byte[] b,int offset,int length)
{
for (int i=0;i>3);
if ((datalen&0x07)!=0) {
databytes++;
}
byte[] recHash=new byte[databytes];
System.arraycopy(mp,mp.length-databytes,recHash,0,databytes);
if ((datalen&0x07)!=0) {
recHash[0]&=(1<<(datalen&0x07))-1;
}
BigInteger hash=new BigInteger(+1, recHash);
BigInteger hash2=new BigInteger(+1, this.dig.digest());
byte[] me2=getMEfromMP(mp,t);
byte[] mr2=getMRfromME(me2,t,z,r);
mr[0] &=(1<<(7-((mr.length <<3)-k)))-1;
mr2[0]&=(1<<(7-((mr2.length<<3)-k)))-1;
return hash.equals(hash2) && Arrays.equals(mr,mr2);
}
// ---------------------------------------------------------------------------------
private static byte[] getISfromSig(byte[] sig,byte[] exp,byte[] mod)
{
return (new BigInteger(+1,sig)).modPow(new BigInteger(+1,exp),new BigInteger(+1,mod)).toByteArray();
}
private static byte[] getIRfromIS(byte[] is,byte[] exp,byte[] mod,int[] ks)
throws SignatureException
{
BigInteger is_b=new BigInteger(+1,is);
BigInteger mod_b=new BigInteger(+1,mod);
BigInteger exp_b=new BigInteger(+1,exp);
BigInteger ret=null;
if (is_b.mod(new BigInteger("16")).equals(new BigInteger("6")))
ret=is_b;
else if (mod_b.subtract(is_b).mod(new BigInteger("16")).equals(new BigInteger("6")))
ret=mod_b.subtract(is_b);
if (ret==null && exp_b.mod(new BigInteger("2")).compareTo(new BigInteger("0"))==0)
if (is_b.mod(new BigInteger("8")).equals(new BigInteger("3")))
ret=is_b.multiply(new BigInteger("2"));
else if (mod_b.subtract(is_b).mod(new BigInteger("8")).equals(new BigInteger("3")))
ret=mod_b.subtract(is_b).multiply(new BigInteger("2"));
if (ret==null) {
throw new SignatureException("can not convert IS to IR");
}
byte[] reta=ret.toByteArray();
int k=reta.length<<3;
for (int idx=0,pos=0;;) {
if ((reta[idx]&(1<<(7-pos)))!=0)
break;
k--;
if (++pos==8) {
pos=0;
idx++;
}
}
ks[0]=k;
if ((reta[reta.length-1]&0x0F)!=0x06)
throw new SignatureException("last nibble is not 0x06");
return reta;
}
private static byte Perm(int b)
{
return (new byte[]{
0x0E, 0x03, 0x05, 0x08,
0x09, 0x04, 0x02, 0x0F,
0x00, 0x0D, 0x0B, 0x06,
0x07, 0x0A, 0x0C, 0x01})[b];
}
private static byte Perm1(int b)
{
return (new byte[]{
0x08, 0x0F, 0x06, 0x01,
0x05, 0x02, 0x0B, 0x0C,
0x03, 0x04, 0x0D, 0x0A,
0x0E, 0x09, 0x00, 0x07})[b];
}
private static byte[] getMRfromIR(byte[] ir,int k,int[] ts)
{
/*
double t2 = ((double)(k)) / 8;
if ((k & 0x07) != 0)
t2 += 1.0;
int t = ((int)(t2)) >> 1;*/
int t=(k-1)>>4;
if (((k-1)&0x0F)!=0)
t++;
ts[0]=t;
byte[] mr=new byte[2*t];
int bitsum=0;
for (int i=0;i<2*t;i++) {
mr[2*t-1-i]=ir[2*t-1-i];
bitsum+=8;
if (bitsum>=k)
mr[2*t-1-i]&=(1<<(7-(bitsum-k)))-1;
}
mr[2*t-1]=(byte)((Perm1((mr[2*t-2]>>4)&0x0F)<<4) | ((mr[2*t-1]>>4)&0x0F));
return mr;
}
private static byte S(int x)
{
return (byte)((Perm((x>>4)&0x0F)<<4) | Perm(x&0x0F));
}
private static byte[] getMPfromMR(byte[] mr,int t,int[] zs,int[] rs)
throws SignatureException
{
int i;
for (i=0;i8)
throw new SignatureException("r is not in range 1..8");
int z=zs[0];
byte[] mp=new byte[z];
for (i=0;i