io.getlime.security.powerauth.lib.util.SignatureUtils Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2016 Lime - HighTech Solutions s.r.o.
*
* 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 io.getlime.security.powerauth.lib.util;
import com.google.common.base.Joiner;
import io.getlime.security.powerauth.lib.config.PowerAuthConfiguration;
import io.getlime.security.powerauth.lib.provider.CryptoProviderUtil;
import javax.crypto.SecretKey;
import java.nio.ByteBuffer;
import java.security.*;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Utility class for signature calculation and validation used both on client and server.
*
* @author Petr Dvorak
*
*/
public class SignatureUtils {
/**
* Compute ECDSA signature of given bytes with a private key.
*
* @param bytes Bytes to be signed.
* @param masterPrivateKey Private key for computing the signature.
* @return Signature for given data.
* @throws InvalidKeyException In case invalid key was provided.
* @throws SignatureException In case signature calculation fails.
*/
public byte[] computeECDSASignature(byte[] bytes, PrivateKey masterPrivateKey) throws InvalidKeyException, SignatureException {
try {
Signature ecdsa = Signature.getInstance("SHA256withECDSA", PowerAuthConfiguration.INSTANCE.getKeyConvertor().getProviderName());
ecdsa.initSign(masterPrivateKey);
ecdsa.update(bytes);
return ecdsa.sign();
} catch (NoSuchAlgorithmException | NoSuchProviderException ex) {
Logger.getLogger(SignatureUtils.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
/**
* Validate an ECDSA signature against given data using a public key.
*
* @param signedBytes Bytes that are signed.
* @param signature Signature of the bytes.
* @param masterPublicKey Public key for validating the signature.
* @return Returns "true" if signature matches, "false" otherwise.
* @throws InvalidKeyException In case invalid key was provided.
* @throws SignatureException In case signature calculation fails.
*/
public boolean validateECDSASignature(byte[] signedBytes, byte[] signature, PublicKey masterPublicKey) throws InvalidKeyException, SignatureException {
try {
Signature ecdsa = Signature.getInstance("SHA256withECDSA", PowerAuthConfiguration.INSTANCE.getKeyConvertor().getProviderName());
ecdsa.initVerify(masterPublicKey);
ecdsa.update(signedBytes);
return ecdsa.verify(signature);
} catch (NoSuchAlgorithmException | NoSuchProviderException ex) {
Logger.getLogger(SignatureUtils.class.getName()).log(Level.SEVERE, null, ex);
}
return false;
}
/**
* Compute PowerAuth 2.0 signature for given data using a secret signature
* keys and counter.
*
* @param data Data to be signed.
* @param signatureKeys Keys for computing the signature.
* @param counter Counter / derived key index.
* @return PowerAuth 2.0 signature for given data.
*
*/
public String computePowerAuthSignature(byte[] data, List signatureKeys, long counter) {
// Prepare a hash
HMACHashUtilities hmac = new HMACHashUtilities();
// Prepare a counter
byte[] ctr = ByteBuffer.allocate(16).putLong(8, counter).array();
// Prepare holder for signature components
String[] signatureComponents = new String[signatureKeys.size()];
CryptoProviderUtil keyConvertor = PowerAuthConfiguration.INSTANCE.getKeyConvertor();
for (int i = 0; i < signatureKeys.size(); i++) {
byte[] signatureKey = keyConvertor.convertSharedSecretKeyToBytes(signatureKeys.get(i));
byte[] derivedKey = hmac.hash(signatureKey, ctr);
for (int j = 0; j < i; j++) {
byte[] signatureKeyInner = keyConvertor.convertSharedSecretKeyToBytes(signatureKeys.get(j + 1));
byte[] derivedKeyInner = hmac.hash(signatureKeyInner, ctr);
derivedKey = hmac.hash(derivedKeyInner, derivedKey);
}
byte[] signatureLong = hmac.hash(derivedKey, data);
if (signatureLong.length < 4) { // assert
throw new IndexOutOfBoundsException();
}
int index = signatureLong.length - 4;
int number = (ByteBuffer.wrap(signatureLong).getInt(index) & 0x7FFFFFFF) % (int) (Math.pow(10, PowerAuthConfiguration.SIGNATURE_LENGTH));
String signature = String.format("%0" + PowerAuthConfiguration.SIGNATURE_LENGTH + "d", number);
signatureComponents[i] = signature;
}
return Joiner.on("-").join(signatureComponents);
}
/**
* Validate the PowerAuth 2.0 signature for given data using provided keys.
*
* @param data Data that were signed.
* @param signature Data signature.
* @param signatureKeys Keys for signature validation.
* @param counter Counter.
* @return Return "true" if signature matches, "false" otherwise.
* @throws InvalidKeyException In case invalid key is provided.
*/
public boolean validatePowerAuthSignature(byte[] data, String signature, List signatureKeys, long counter) throws InvalidKeyException {
return signature.equals(computePowerAuthSignature(data, signatureKeys, counter));
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy