Error trying to verify signature on CBOR message - java

I'm having problems decoding EU Digital Certificate ("Covid pass") using COSE-JAVA. Public key appears to load ok but when I try to validate the CBOR message, I get following error:
COSE.CoseException: Signature verification failure
at COSE.SignCommon.validateSignature(SignCommon.java:205)
at COSE.Signer.validate(Signer.java:212)
at COSE.Message.validate(Message.java:288)
Caused by: java.lang.NullPointerException: Attempt to get length of null array
at COSE.SignCommon.convertConcatToDer(SignCommon.java:212)
Here is code for validation:
public static String DecodeMessage(byte[] data) throws CoseException, CborParseException {
Message m = Encrypt0Message.DecodeFromBytes(data);
PublicKey key = getPublicKey("here goes PEM of public key");
CborMap cborMap = CborMap.createFromCborByteArray(m.GetContent());
CounterSign signer = new CounterSign();
signer.setKey(new OneKey(key, null));
signer.addAttribute(HeaderKeys.Algorithm, AlgorithmID.ECDSA_256.AsCBOR(), Attribute.ProtectedAttributes);
// error happens here
m.validate(signer);
return cborMap.toJsonString();
}
This is how public key is generated from PEM:
public static PublicKey getPublicKey(String keyData) {
try
{
Security.removeProvider("BC");
Security.addProvider(new BouncyCastleProvider());
Reader rdr = new StringReader(
"-----BEGIN EC PUBLIC KEY-----\n" + keyData + "\n" + "-----END EC PUBLIC KEY-----\n"
);
org.bouncycastle.util.io.pem.PemObject spki = new org.bouncycastle.util.io.pem.PemReader(rdr).readPemObject();
byte[] content = spki.getContent();
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(content);
return KeyFactory.getInstance("EC", "BC").generatePublic(pubKeySpec);
}
catch (Exception ex)
{
return null;
}
Public key is defined as:
"publicKeyAlgorithm": {
"hash": {
"name": "SHA-256"
},
"name": "ECDSA",
"namedCurve": "P-256"
},
"publicKeyPem": "..."
Here is code for doing same thing in Python, might help someone. Code must work on Android 7.1 (embedded device, no way to upgrade to newer Android).

Solved...
public static boolean VerifySignature(byte[] data, String publicKey) {
boolean result = false;
try {
Message m = Encrypt0Message.DecodeFromBytes(data);
Sign1Message sm = (Sign1Message) m;
PublicKey key = getPublicKey(publicKey);
if (sm.validate(new OneKey(key, null))) {
result = true;
}
} catch (Exception ex) {
log.error("Error verifying signature", ex);
}
return result;
}
and
public static PublicKey getPublicKey(String keyData) {
try {
Security.removeProvider("BC");
Security.addProvider(new BouncyCastleProvider());
Reader rdr = new StringReader(
"-----BEGIN EC PUBLIC KEY-----\n" + keyData + "\n" + "-----END EC PUBLIC KEY-----\n"
);
org.bouncycastle.util.io.pem.PemObject spki = new org.bouncycastle.util.io.pem.PemReader(rdr).readPemObject();
byte[] content = spki.getContent();
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(content);
return KeyFactory.getInstance("EC", "BC").generatePublic(pubKeySpec);
} catch (Exception ex) {
return null;
}
}

ODqaG8mnbro=": {
"serialNumber": "5dfefffd3a560d58",
"subject": "C=BE, O=eHealth - Belgium, CN=Belgium Covid19 DSC 01",
"issuer": "C=BE, O=eHealth - Belgium, CN=Belgium Covid19 Country Signing CA 01",
"notBefore": "2021-05-27T10:12:47.000Z",
"notAfter": "2023-05-27T10:12:47.000Z",
"signatureAlgorithm": "ECDSA",
"fingerprint": "2942d10907cf19f27aeb0dc391f35197c69dea87",
"publicKeyAlgorithm": {
"hash": {
"name": "SHA-256"
},
"name": "ECDSA",
"namedCurve": "P-256"
},
"publicKeyPem": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEU/f/KsmP3NasU/jZo7aulTrd9GHoznfnwWvX8xmHtK49EoobMAG7LhXnpLQ+aRwmmnSMcIWy8wPxM8QDMBUtyA=="
}

Related

Encrypt/Decrypt String using Public/Private Key in Java and Javascript

I am generating a public and private key pair in javascript. The public key is being sent to the server where I have java code that encrypts the string. When I try to decrypt the string in Javascript using a private key I get an error. Here is the Javascript code I used.
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root'
})
export class CryptographyService {
private publicKey: string;
private privateKey: string;
public randomKey: string;
private keyPair: CryptoKeyPair;
public exportedKey: string;
constructor() {
/**Generate the public and private key */
this.generateKeys()
.then(() => {
return this.exportKey(this.keyPair.publicKey);
})
.then(() => {});
}
public setPublicKey(key: string) {
this.publicKey = key;
}
public setRandomKey(key: string) {
this.randomKey = key;
}
public setPrivateKey(key: string) {
this.privateKey = key;
}
public async encryptMessage(text: String) {
const { default: NodeRSA } = await import('node-rsa');
const key = NodeRSA(this.publicKey, 'pkcs8-public');
return key.encrypt(text, 'base64');
}
// For subscription key encryption and decryption
private async generateKeys() {
const keyPair = await crypto.subtle.generateKey(
{
name: 'RSA-OAEP', //algorithm
modulusLength: 2048,
publicExponent: new Uint8Array([1, 0, 1]),
hash: 'SHA-256'
},
true,
['encrypt', 'decrypt']
);
this.keyPair = keyPair; /**{
publicKey:
privateKey:
} */
}
private async exportKey(key: CryptoKey) {
/** exportKey() it takes as input a CryptoKey object and gives you the key in an external, portable format.
* crypto.subtle.exportKey(format, key); : returns a promise
* spki format is used to import/export RSA or Elliptic Curve public keys.
*/
const exported = await crypto.subtle.exportKey('spki', key); //Returns an ArrayBuffer
const exportedAsString = this.ab2str(exported); // Converts ArrayBuffer to String
/**btoa encodes a string to base64 */
const exportedAsBase64 = window.btoa(exportedAsString);
this.exportedKey = exportedAsBase64;
}
// Uses private key to decrypt message sent from the backend
public async decryptMessage(input: string) {
const ciphertext = this.str2ab(input);
const decrypted = await window.crypto.subtle.decrypt(
{
name: 'RSA-OAEP'
},
this.keyPair.privateKey,
ciphertext
);
const dec = new TextDecoder();
const decodedMessage = dec.decode(decrypted);
return decodedMessage;
}
private ab2str(buf) {
return String.fromCharCode.apply(null, new Uint8Array(buf));
}
private str2ab(str) {
const buf = new ArrayBuffer(str.length);
const bufView = new Uint8Array(buf);
for (let i = 0, strLen = str.length; i < strLen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
}
}
The java code to convert the string to PublicKey Object
String pubKey = loginRequest.publicKey;
PublicKey pk = null;
try {
byte[] keyBytes = Base64.decodeBase64(pubKey);
X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
pk = kf.generatePublic(spec);
} catch (Exception e) {
System.out.println("Exception in generating primary key: " + e.getMessage());
}
Encrypting the string with the publicKey
public static byte[] encrypt(String text, PublicKey key) {
byte[] cipherText = null;
try {
// get an RSA cipher object and print the provider
final Cipher cipher = Cipher.getInstance(ALGORITHM);
OAEPParameterSpec oaepParams = new OAEPParameterSpec("SHA-256", "MGF1", new MGF1ParameterSpec("SHA-256"), PSource.PSpecified.DEFAULT);
// encrypt the plain text using the public key
cipher.init(Cipher.ENCRYPT_MODE, key, oaepParams);
cipherText = cipher.doFinal(text.getBytes());
} catch (Exception e) {
e.printStackTrace();
}
return cipherText;
}
I get back an encrypted string when when I try to decode it in Javascript I get an error. Any idea what I need to change in my code to fix this?

Error to validate ECDSA signature in pkcs7

I have successfully generate pkcs7 signature ECDSAwithSHA256 using C# , but then i failed to verify signature using java
Here is sample class
public class TestVerify {
public static void main(String[] args) {
String Signature = "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";
String SigDateTime = "14-10-2020 10:58:22";
String certtype = "token";
String TimestampToken = "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";
String pdfhash = "faadTnFU4cOBsl+sW98ie7KInSbbw0HDbgFeOcsRCAQ=";
CMSSignedData signedDataTSToken = null;
TimeStampToken tstoken = null;
byte[] sigDataBytes = null;
Date sigDate = null;
CMSSignerHelper cmsHelper = new CMSSignerHelper();
CMSSignedData cmsData;
try {
sigDataBytes = Base64.getDecoder().decode(Signature);
cmsData = new CMSSignedData(sigDataBytes);
DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
sigDate = formatter.parse(SigDateTime);
byte[] tsTokenDataBytes = Base64.getDecoder().decode(TimestampToken);
signedDataTSToken = new CMSSignedData(tsTokenDataBytes);
tstoken = new TimeStampToken(signedDataTSToken);
verifyCMSSignatureMTID(sigDataBytes, sigDate, TimestampToken, pdfhash);
} catch (Exception e) {
System.out.println("Exception : " + e);
}
}
public static void verifyCMSSignatureMTID(byte[] signature, Date signing_date, String encodedTimestampToken, String PdfHash) throws OperatorCreationException, CMSException, CertificateException, NoSuchAlgorithmException, ParseException, TSPException, IOException, Exception {
String fName="[verifyCMSSignatureMTID] ";
VSInfo vsi=new VSInfo();
String initErr="CMS";
//******************** VERIFY SGNATURE VS SIGNER PUBLICKEY **********************
// Verify signature
byte[] HashByte = Base64.getDecoder().decode(PdfHash);
CMSProcessableByteArray processable = new CMSProcessableByteArray(HashByte);
CMSSignedData cmsData = new CMSSignedData(signature);
X509CertificateHolder certHolder_v=null;
Security.addProvider(new BouncyCastleProvider());
try {
Store store = cmsData.getCertificates();
ByteArrayInputStream stream = new ByteArrayInputStream(signature);
CMSSignedData cms = new CMSSignedData(processable, stream);
SignerInformationStore signers = cms.getSignerInfos();
Collection c_v = signers.getSigners();
Iterator it_v = c_v.iterator();
while (it_v.hasNext()) {
SignerInformation signer_v = (SignerInformation) it_v.next();
Collection certCollection_v = store.getMatches(signer_v.getSID());
Iterator certIt_v = certCollection_v.iterator();
certHolder_v = (X509CertificateHolder) certIt_v.next();
X509Certificate certFromSignedData_v = new JcaX509CertificateConverter().getCertificate(certHolder_v);
if (signer_v.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BouncyCastleProvider.PROVIDER_NAME).build(certFromSignedData_v))) {
System.out.println(fName + "Signature verified");
} else {
System.out.println(fName + "Error CMS200 Signature is invalid");
System.out.println(initErr+"200");
System.out.println("Signature is invalid");
return;
}
}
} catch (Exception e) {
e.printStackTrace();
System.out.println(fName + "Error CMS200 Signature is invalid : " + e);
System.out.println("200");
System.out.println("Signature is invalid");
return;
}
System.out.println("000");
System.out.println("Signature is valid");
return;
}
}
Error
org.bouncycastle.operator.RuntimeOperatorException: exception
obtaining signature: error decoding signature bytes.
However, i have succesfully verify RSAwithSHA256 signature using this method. Can someone help me on this and kindly explain what that error is about. The signature length for those signature is 256byte for RSA and 64byte for ECDSA . is it correct?

How to implement google play security verify purchase server side?

I want to implement in-app purchase verification server-side in PHP language.
I tested this link but returned false for correct data set.
The java function:
public class Security {
private static final String TAG = "IABUtil/Security";
private static final String KEY_FACTORY_ALGORITHM = "RSA";
private static final String SIGNATURE_ALGORITHM = "SHA1withRSA";
public static boolean verifyPurchase(String base64PublicKey, String signedData, String signature) {
if (TextUtils.isEmpty(signedData) || TextUtils.isEmpty(base64PublicKey) ||
TextUtils.isEmpty(signature)) {
Log.e(TAG, "Purchase verification failed: missing data.");
return false;
}
PublicKey key = Security.generatePublicKey(base64PublicKey);
return Security.verify(key, signedData, signature);
}
public static PublicKey generatePublicKey(String encodedPublicKey) {
try {
byte[] decodedKey = Base64.decode(encodedPublicKey);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_FACTORY_ALGORITHM);
return keyFactory.generatePublic(new X509EncodedKeySpec(decodedKey));
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
} catch (InvalidKeySpecException e) {
Log.e(TAG, "Invalid key specification.");
throw new IllegalArgumentException(e);
} catch (Base64DecoderException e) {
Log.e(TAG, "Base64 decoding failed.");
throw new IllegalArgumentException(e);
}
}
public static boolean verify(PublicKey publicKey, String signedData, String signature) {
...
}
}
I tried this code:
function verify_market_in_app($signed_data, $signature, $public_key_base64)
{
$key = "-----BEGIN PUBLIC KEY-----\n".
chunk_split($public_key_base64, 64,"\n").
'-----END PUBLIC KEY-----';
//using PHP to create an RSA key
$key = openssl_get_publickey($key);
//$signature should be in binary format, but it comes as BASE64.
//So, I'll convert it.
$signature = base64_decode($signature);
//using PHP's native support to verify the signature
$result = openssl_verify(
$signed_data,
$signature,
$key,
OPENSSL_ALGO_SHA1);
if (0 === $result)
{
return false;
}
else if (1 !== $result)
{
return false;
}
else
{
return true;
}
}
but this isn't work correctly.
I use openssl_error_string() function and get this error:
error:0906D064:PEM routines:PEM_read_bio:bad base64 decode
Can any body help?

BadPaddingException decrypting the encrypted data in Android

I'm new to Android security concepts.
I have been reading some blogs to get to know about we can encrypt data using Public key and can decrypt it using respective Private key. Encryption seems to be doesn't have any problem, but when I try to decrypt it, it throws:
javax.crypto.BadPaddingException: error:0407106B:rsa routines:RSA_padding_check_PKCS1_type_2:block type is not 02.
My code is as follows:
public String RSAEncrypt(final String plain, PublicKey publicKey ) throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte [] encryptedBytes = cipher.doFinal(plain.getBytes());
String encrypted = bytesToString(encryptedBytes);
System.out.println("EEncrypted?????" + encrypted );
return encrypted;
}
public String RSADecrypt(String encryptedBytes,PrivateKey privateKey ) throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, IllegalBlockSizeException, BadPaddingException, NoSuchProviderException {
Cipher cipher1 = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher1.init(Cipher.DECRYPT_MODE, privateKey);
byte [] decryptedBytes = cipher1.doFinal(stringToBytes(encryptedBytes));
String decrypted = new String(decryptedBytes);
System.out.println("DDecrypted?????" + decrypted);
return decrypted;
}
public String bytesToString(byte[] b) {
byte[] b2 = new byte[b.length + 1];
b2[0] = 1;
System.arraycopy(b, 0, b2, 1, b.length);
return new BigInteger(b2).toString(36);
}
public byte[] stringToBytes(String s) {
byte[] b2 = new BigInteger(s, 36).toByteArray();
return Arrays.copyOfRange(b2, 1, b2.length);
}
Stack trace is as follows:
07-28 11:27:35.119: I/System.out(22933): KEYSTORE : String to encrypt = > Hello
07-28 11:27:35.119: I/System.out(22933): KEYSTORE : [B#41bbf4d0
07-28 11:27:38.422: I/System.out(22933): KEYSTORE : String to Decrypt = > UJGAchuDhu3mqH5YPjmYqKBapJYMjJRk9g6HIy8bANooWorzwqgiEo+dOse6Nfq7i0yzw/Wt7TSdTNiYROxehkZvEx/mW5+Niw1CgZ2y9b/ijTeNTF+7aGPrqfDXJ38hUFdTPc6oNl2FVOIafncGOSK9po1JOAYeK0JiA2KrACfPLPjsLQSRzseThyYGxttRM7qbx/N0VTmlTeuNpLFld8Gtw3fHR8UoLGkH/OTFYPLZBVNE8t/oCCy8FpcCu9SGXxF8vh1R4rq15bfyyh9sBU9RuVtoLM0wDSbKixHhNOwwx2Z/A+SHDaQD9C+x3p1AnS9FYZm0Y07E+VYQWqzOpw
07-28 11:27:38.562: W/System.err(22933): javax.crypto.BadPaddingException: error:0407106B:rsa routines:RSA_padding_check_PKCS1_type_2:block type is not 02
07-28 11:27:41.515: D/WifiNative-wlan0(773): doString: SIGNAL_POLL
07-28 11:27:41.515: W/WifiHW(773): QCOM Debug wifi_send_command "IFNAME=wlan0 SIGNAL_POLL"
07-28 11:27:41.525: D/wpa_supplicant(16189): nl80211: survey data missing!
07-2
07-28 11:27:56.612: W/WifiHW(773): QCOM Debug wifi_send_command "IFNAME=wlan0 SIGNAL_POLL"
07-28 11:27:56.612: D/wpa_supplicant(16189): nl80211: survey data missing!
07-28 11:27:56.622: I/wpa_supplicant(16189): environment dirty rate=0 [0][0][0]
07-28 11:27:56.622: D/WifiStateMachine(773): fetchRssiAndLinkSpeedNative RSSI = -62 abnormalRssiCnt = 0 newLinkSpeed = 58
07-28 11:27:56.622: D/WifiStateMachine(773): fetchRssiAndLinkSpeedNative mLinkspeedCount = 2, mLinkspeedSum: 116
I'm not sure where am going wrong.
A BadPaddingException occurs when the padding (bytes to fill up a too small encryption block) doesn't match a specified format (for example PKCS1, OAEP, ...). This can have a few causes:
You are using a different mode of RSA for en- and decryption.
The data (the byte[]) you get from encryption is not the same as the one you pass to decryption.
(You are using an incorrect KeyPair.)
Since you are initializing RSA with getInstance("RSA") for encryption and getInstance("RSA/ECB/PKCS1Padding") for decryption, it could be possible that ECB/PKCS1Padding is not the default on Android (even though it should be on Desktop-Java).
So try this in RSAEncrypt():
cipher.getInstance("RSA/ECB/PKCS1Padding");
If this does not work, make sure that you pass the exact same byte[] you get from cipher.doFinal() in encryption to cipher.doFinal() in decryption.
(Your code does work on my Desktop Java7 btw.)
you must break message to blocks.
can use below class.
// Note: RSA has block limitation, text size must < (SIZE/8) , otherwise you see [too much data for RSA block]
public class RSA
{
private RSAPublicKey internalPublicKey;
private RSAPrivateCrtKey internalPrivateKey;
private int SIZE = -1;
private String cipherAlgorithm = "RSA/None/PKCS1PADDING";
private String keyAlgorithm = "RSA";
private int b64State = Base64.NO_WRAP;
private static int b64State_static = Base64.NO_WRAP;
public RSA(int size)
{
SIZE = size;
init();
}
public RSA(int size, RSAPublicKey puk, RSAPrivateCrtKey prk)
{
if(puk == null)
throw new RuntimeException("Err: PublicKey is null.");
if(prk != null)
{
if(!puk.getModulus().equals(prk.getModulus()))
throw new RuntimeException("Err: PublicKey not matched by PrivateKey.");
}
SIZE = size;
internalPublicKey = puk;
internalPrivateKey = prk;
}
private void init()
{
try
{
//SecretKeyFactory keyFac = SecretKeyFactory.getInstance("PBEWithSHA256And256BitAES-CBC-BC");
KeyPairGenerator kpg = KeyPairGenerator.getInstance(keyAlgorithm);
kpg.initialize(SIZE); //initialize(SIZE, new SecureRandom());
KeyPair kp = kpg.genKeyPair();
internalPublicKey = (RSAPublicKey) kp.getPublic();
internalPrivateKey = (RSAPrivateCrtKey) kp.getPrivate();
}
catch(Exception e)
{throw new RuntimeException("Err: init RSA. " + e.toString());}
}
public int getSize()
{
return SIZE;
}
public RSAPublicKey getPublicKey()
{
return internalPublicKey;
}
public RSAPrivateCrtKey getPrivateKey()
{
return internalPrivateKey;
}
public String getPublicModule()
{
String s = internalPublicKey.toString();
return s.substring(s.indexOf("modulus")+8, s.indexOf(",publicExponent"));
}
public BigInteger getPublicModuleInt()
{
return internalPublicKey.getModulus();
}
public String getPublicExponent()
{
String s = internalPublicKey.toString();
return s.substring(s.indexOf("publicExponent")+15, s.lastIndexOf("}"));
}
public BigInteger getPublicExponentInt()
{
return internalPublicKey.getPublicExponent();
}
public String getPrivateExponent()
{
String s = internalPrivateKey.toString();
return s.substring(s.indexOf("privateExponent")+16, s.indexOf(",primeP"));
}
public String getPrimP()
{
String s = internalPrivateKey.toString();
return s.substring(s.indexOf("primeP=")+7, s.indexOf(",primeQ"));
}
public String getPrimQ()
{
String s = internalPrivateKey.toString();
return s.substring(s.indexOf("primeQ=")+7, s.indexOf(",primeExponentP"));
}
public String getPrimExponentP()
{
String s = internalPrivateKey.toString();
return s.substring(s.indexOf("primeExponentP=")+15, s.indexOf(",primeExponentQ"));
}
public String getPrimExponentQ()
{
String s = internalPrivateKey.toString();
return s.substring(s.indexOf("primeExponentQ=")+15, s.indexOf(",crtCoefficient"));
}
public String getCrtCoefficient()
{
String s = internalPrivateKey.toString();
return s.substring(s.indexOf("crtCoefficient=")+15, s.lastIndexOf(","));
}
public byte[] getPublicKeyAsByte()
{
return internalPublicKey.getEncoded();
}
public byte[] getPrivateKeyAsByte()
{
return internalPrivateKey.getEncoded();
}
public void changeCipherAlgorithm(String algorithm)
{
cipherAlgorithm = algorithm;
}
public byte[] getEncrypt(byte[] plain)
{
try
{
Cipher cipher = Cipher.getInstance(cipherAlgorithm);
cipher.init(Cipher.ENCRYPT_MODE, internalPublicKey);
return cipher.doFinal(plain);
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "Err: getEncrypt(byte[] plain), ", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public byte[] getEncrypt(String plain)
{
try
{
return getEncrypt(plain.getBytes("UTF-8"));
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "Err: getEncrypt(String x), ", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public String getEncryptToB64(byte[] plain)
{
return Base64.encodeToString(getEncrypt(plain), b64State);
}
public byte[] getLargeEncrypt(byte[] plain, boolean byPadding) //byPadding = true if use RSA/xxx/xxxPADDING
{
ByteArrayOutputStream out = new ByteArrayOutputStream();
try
{
int n = byPadding ? (getSize()/8) -11: (getSize()/8);
int offset = 0;
while(offset < plain.length)
{
byte[] section = Arrays.copyOfRange(plain, offset, Math.min(offset+n, plain.length));
byte[] cache = getEncrypt(section);
out.write(cache, 0, cache.length);
offset += n;
}
return out.toByteArray();
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "Err: getLargeEncrypt(String x), ", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public byte[] getLargeEncrypt(String plain, boolean byPadding) //byPadding = true if use RSA/xxx/xxxPADDING
{
return getLargeEncrypt(plain.getBytes(Charset.forName("UTF-8")), byPadding);
}
public String getLargeEncryptToB64(String plain, boolean byPadding) //byPadding = true if use RSA/xxx/xxxPADDING
{
return Base64.encodeToString(getLargeEncrypt(plain, byPadding), Base64.NO_WRAP);
}
public String getLargeEncryptToB64Block(String plain, boolean byPadding) //byPadding = true if use RSA/xxx/xxxPADDING
{
StringBuilder sb = new StringBuilder();
try
{
byte[] enc = plain.getBytes("UTF-8");
int n = byPadding ? (getSize()/8) -11: (getSize()/8);
int offset = 0;
while(offset < enc.length)
{
byte[] section = Arrays.copyOfRange(enc, offset, Math.min(offset+n, enc.length));
sb.append(getEncryptToB64(section));
offset += n;
}
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "Err: getLargeEncryptToB64Block(String x), ", Constants.DEFAULT_ALERT_STATE);
}
return sb.toString();
}
public String getLargeDecryptFromB64Block(String enc)
{
ByteArrayOutputStream out = new ByteArrayOutputStream();
try
{
int n = (getSize()/8)-11;
int x = getEncryptToB64(TextHelper.generateString(n).getBytes("UTF-8")).length();
String[] ex = TextHelper.splitFix(enc, x);
for(int i=0; i<ex.length; i++)
{
byte[] sec = Base64.decode(ex[i], Base64.NO_WRAP);
out.write(sec, 0, sec.length);
//sb.append(getDecryptFromB64(ex[i]));
}
return getLargeDecryptToString(out.toByteArray());//sb.toString()
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "Err: getLargeDecryptFromB64Block(String x), ", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public byte[] getLargeDecrypt(byte[] enc)
{
ByteArrayOutputStream out = new ByteArrayOutputStream();
try
{
int n = (getSize()/8);
int offset = 0;
while(offset < enc.length)
{
byte[] section = Arrays.copyOfRange(enc, offset, Math.min(offset+n, enc.length));
byte[] cache = getDecrypt(section);
out.write(cache, 0, cache.length);
offset += n;
}
return out.toByteArray();
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "Err: getLargeDecrypt(byte[] x), ", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public String getLargeDecryptToString(byte[] enc)
{
return new String(getLargeDecrypt(enc), Charset.forName("UTF-8"));
}
public String getLargeDecryptFromB64(String encB64)
{
return getLargeDecryptToString(Base64.decode(encB64, Base64.NO_WRAP));
}
public byte[] getDecrypt(byte[] encryptedBytes)
{
try
{
Cipher cipher = Cipher.getInstance(cipherAlgorithm);
cipher.init(Cipher.DECRYPT_MODE, internalPrivateKey);
return cipher.doFinal(encryptedBytes);
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "Err: getDecrypt(byte[] x), ", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public String getDecryptFromB64(String encrypted)
{
try
{
byte[] b = Base64.decode(encrypted.getBytes("UTF-8"), b64State);
return getDecryptAsString(b);
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "Err: getDecryptFromB64(String x), ", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public String getDecryptAsString(byte[] encryptedBytes)
{
return new String(getDecrypt(encryptedBytes), Charset.forName("UTF-8"));
}
public static byte[] getEncrypt(byte[] plain, PublicKey pk, Cipher cipher)
{
try
{
cipher.init(Cipher.ENCRYPT_MODE, pk);
return cipher.doFinal(plain);
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "Err: getEncrypt(byte[] x, PublicKey pk, Cipher cipher), ", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public static byte[] getEncrypt(String plain, PublicKey pk, Cipher cipher)
{
try
{
return getEncrypt(plain.getBytes("UTF-8"), pk, cipher);
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "Err: getEncrypt(String x, PublicKey pk, Cipher cipher), ", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public static byte[] getDecrypt(byte[] encryptedBytes, PrivateKey pk, Cipher cipher)
{
try
{
cipher.init(Cipher.DECRYPT_MODE, pk);
return cipher.doFinal(encryptedBytes);
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public static String getDecryptAsString(byte[] encryptedBytes, PrivateKey pk, Cipher cipher)
{
try
{
return new String(getDecrypt(encryptedBytes, pk, cipher), "UTF-8");
}
catch(Exception e){}
return null;
}
public static byte[] getDecrypt(final byte[] encryptedBytes, byte[] privateKey, Cipher cipher)
{
try
{
KeyFactory keyFac = KeyFactory.getInstance("RSA");
KeySpec keySpec = new PKCS8EncodedKeySpec(privateKey);
PrivateKey pk = keyFac.generatePrivate(keySpec);
cipher.init(Cipher.DECRYPT_MODE, pk);
return cipher.doFinal(encryptedBytes);
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public static String getDecryptAsString(final byte[] encryptedBytes, byte[] privateKey, Cipher cipher)
{
return new String(getDecrypt(encryptedBytes, privateKey, cipher), Charset.forName("UTF-8"));
}
public static byte[] sign(byte[] forSign, PrivateKey byThisKey)
{
try
{
Signature privateSignature = Signature.getInstance("SHA1withRSA");//or SHA256withRSA
privateSignature.initSign(byThisKey);
privateSignature.update(forSign);
return privateSignature.sign();
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "Err: sign(), ", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public static String sign(String forSign, PrivateKey byThisKey)
{
return Base64.encodeToString(sign(forSign.getBytes(), byThisKey), b64State_static);
}
public static boolean verify(String plainText, String signature, PublicKey publicKey)
{
Signature publicSignature;
try
{
publicSignature = Signature.getInstance("SHA1withRSA");
publicSignature.initVerify(publicKey);
publicSignature.update(plainText.getBytes());
byte[] signatureBytes = Base64.decode(signature, b64State_static);
return publicSignature.verify(signatureBytes);
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "Err: verify(), ", Constants.DEFAULT_ALERT_STATE);
}
return false;
}
public static RSAPublicKey generatePublicKey(String modulus, String exponent)
{
try
{
BigInteger modBigInteger = new BigInteger(modulus, 16);
BigInteger exBigInteger = new BigInteger(exponent, 16);
RSAPublicKeySpec spec = new RSAPublicKeySpec(modBigInteger, exBigInteger);
KeyFactory factory = KeyFactory.getInstance("RSA");
return (RSAPublicKey) factory.generatePublic(spec);
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "Err: getEncrypt(), ", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public static RSAPublicKey generatePublicKey(BigInteger modulus, BigInteger exponent)
{
try
{
RSAPublicKeySpec spec = new RSAPublicKeySpec(modulus, exponent);
KeyFactory factory = KeyFactory.getInstance("RSA");
return (RSAPublicKey) factory.generatePublic(spec);
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "Err: getEncrypt(), ", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public static RSAPublicKey generatePublicKeyFromDotNet(String modulus, String exponent)
{
return generatePublicKey(RSA.parseDotNetBigInt(modulus), RSA.parseDotNetBigInt(exponent));
}
public static RSAPrivateCrtKey generatePrivateKeyFromDotNet(String modulus, String pubEx, String priEx, String p, String q, String dp, String dq,String invQ)
{
return generatePrivateKey(RSA.parseDotNetBigInt(modulus), RSA.parseDotNetBigInt(pubEx), RSA.parseDotNetBigInt(priEx), RSA.parseDotNetBigInt(p)
,RSA.parseDotNetBigInt(q),RSA.parseDotNetBigInt(dp), RSA.parseDotNetBigInt(dq), RSA.parseDotNetBigInt(invQ));
}
public static PublicKey generateBCPublicKey(String modulus, String exponent)
{
try
{
BigInteger modBigInteger = new BigInteger(modulus, 16);
BigInteger exBigInteger = new BigInteger(exponent, 16);
RSAPublicKeySpec spec = new RSAPublicKeySpec(modBigInteger, exBigInteger);
KeyFactory factory = KeyFactory.getInstance("RSA", "BC");
return factory.generatePublic(spec);
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "Err: getBCPublicKey(), ", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public static RSAPrivateCrtKey generatePrivateKey(String modulus, String publicExpo, String privateExpo, String primP, String primQ, String ePrimP, String ePrimQ, String cof)
{
try
{
BigInteger module = new BigInteger(modulus, 16);
BigInteger expo1 = new BigInteger(publicExpo, 16);
BigInteger expo2 = new BigInteger(privateExpo, 16);
BigInteger prim_P = new BigInteger(primP, 16);
BigInteger prim_Q = new BigInteger(primQ, 16);
BigInteger prim_EP = new BigInteger(ePrimP, 16);
BigInteger prim_EQ = new BigInteger(ePrimQ, 16);
BigInteger coefficient = new BigInteger(cof, 16);
/*BigInteger module = new BigInteger(1, Base64.encode(modulus.getBytes(), b64State));*/
RSAPrivateCrtKeySpec spec = new RSAPrivateCrtKeySpec(module, expo1, expo2, prim_P, prim_Q, prim_EP, prim_EQ, coefficient);
KeyFactory factory = KeyFactory.getInstance("RSA");
return (RSAPrivateCrtKey) factory.generatePrivate(spec);
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public static RSAPrivateCrtKey generatePrivateKey(BigInteger modulus, BigInteger publicExpo, BigInteger privateExpo, BigInteger primP, BigInteger primQ, BigInteger ePrimP, BigInteger ePrimQ, BigInteger cof)
{
try
{
RSAPrivateCrtKeySpec spec = new RSAPrivateCrtKeySpec(modulus, publicExpo, privateExpo, primP, primQ, ePrimP, ePrimQ, cof);
KeyFactory factory = KeyFactory.getInstance("RSA");
return (RSAPrivateCrtKey) factory.generatePrivate(spec);
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public static PrivateKey generateBCPrivateKey(String modulus, String publicExpo, String privateExpo, String primP, String primQ, String ePrimP, String ePrimQ, String cof)
{
try
{
BigInteger module = new BigInteger(modulus, 16);
BigInteger expo1 = new BigInteger(publicExpo, 16);
BigInteger expo2 = new BigInteger(privateExpo, 16);
BigInteger prim_P = new BigInteger(primP, 16);
BigInteger prim_Q = new BigInteger(primQ, 16);
BigInteger prim_EP = new BigInteger(ePrimP, 16);
BigInteger prim_EQ = new BigInteger(ePrimQ, 16);
BigInteger coefficient = new BigInteger(cof, 16);
RSAPrivateCrtKeySpec spec = new RSAPrivateCrtKeySpec(module, expo1, expo2, prim_P, prim_Q, prim_EP, prim_EQ, coefficient);
KeyFactory factory = KeyFactory.getInstance("RSA", "BC");
return factory.generatePrivate(spec);
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public static Cipher generateCipher(String alg,#Nullable String provider)
{
try
{
if(provider == null)
return Cipher.getInstance(alg);
else
return Cipher.getInstance(alg, provider);
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "Err: generateCipher(), ", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public static BigInteger parseDotNetBigInt(String b64BigInt)
{
try
{
String modulusHex = Hex.encodeHex(Base64.decode(b64BigInt.getBytes("UTF-8"), Base64.NO_WRAP));
return new BigInteger(modulusHex, 16);
}
catch (Exception ex)
{
ThreadHelper.exceptionAlert(ex, Constants.TAG_FOR_LOG, "Err: parseDotNetBigInt(),", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public static String privateKeyToXMLString(RSAPrivateCrtKey key)
{
try
{
Document xml = privateKeyToXML(key);
Transformer transformer = TransformerFactory.newInstance().newTransformer();
StringWriter sw = new StringWriter();
transformer.transform(new DOMSource(xml), new StreamResult(sw));
return sw.getBuffer().toString();
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "Err: privateKeyToXMLString(RSAPrivateCrtKey x),", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public static String publicKeyToXMLString(RSAPublicKey key)
{
try
{
Document xml = publicKeyToXML(key);
Transformer transformer = TransformerFactory.newInstance().newTransformer();
StringWriter sw = new StringWriter();
transformer.transform(new DOMSource(xml), new StreamResult(sw));
return sw.getBuffer().toString();
}
catch(Exception e){}
return null;
}
public static Document publicKeyToXML(RSAPublicKey key)
{
try
{
Document result = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
Element rsaKeyValue = result.createElement("RSAKeyValue");
result.appendChild(rsaKeyValue);
Element modulus = result.createElement("Modulus");
rsaKeyValue.appendChild(modulus);
byte[] modulusBytes = key.getModulus().toByteArray();
modulusBytes = stripLeadingZeros(modulusBytes);
modulus.appendChild(result.createTextNode(new String(Base64.encode(modulusBytes, b64State_static))));
Element exponent = result.createElement("Exponent");
rsaKeyValue.appendChild(exponent);
byte[] exponentBytes = key.getPublicExponent().toByteArray();
exponent.appendChild(result.createTextNode(new String(Base64.encode(exponentBytes, b64State_static))));
return result;
}
catch(Exception e){}
return null;
}
public static Document privateKeyToXML(RSAPrivateCrtKey key)
{
try
{
Document result = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
Element rsaKeyValue = result.createElement("RSAKeyValue");
result.appendChild(rsaKeyValue);
Element modulus = result.createElement("Modulus");
rsaKeyValue.appendChild(modulus);
Element exponent = result.createElement("Exponent");
rsaKeyValue.appendChild(exponent);
Element P = result.createElement("P");
rsaKeyValue.appendChild(P);
Element Q = result.createElement("Q");
rsaKeyValue.appendChild(Q);
Element DP = result.createElement("DP");
rsaKeyValue.appendChild(DP);
Element DQ = result.createElement("DQ");
rsaKeyValue.appendChild(DQ);
Element InverseQ = result.createElement("InverseQ");
rsaKeyValue.appendChild(InverseQ);
Element D = result.createElement("D");
rsaKeyValue.appendChild(D);
byte[] modulusBytes = key.getModulus().toByteArray();
modulusBytes = stripLeadingZeros(modulusBytes);
modulus.appendChild(result.createTextNode(new String(Base64.encode(modulusBytes, b64State_static))));
byte[] pubExponent = key.getPublicExponent().toByteArray();
exponent.appendChild(result.createTextNode(new String(Base64.encode(pubExponent, b64State_static))));
byte[] p = key.getPrimeP().toByteArray();
P.appendChild(result.createTextNode(new String(Base64.encode(p, b64State_static))));
byte[] q = key.getPrimeQ().toByteArray();
Q.appendChild(result.createTextNode(new String(Base64.encode(q, b64State_static))));
byte[] ep = key.getPrimeExponentP().toByteArray();
DP.appendChild(result.createTextNode(new String(Base64.encode(ep, b64State_static))));
byte[] eq = key.getPrimeExponentP().toByteArray();
DQ.appendChild(result.createTextNode(new String(Base64.encode(eq, b64State_static))));
byte[] cof = key.getCrtCoefficient().toByteArray();
InverseQ.appendChild(result.createTextNode(new String(Base64.encode(cof, b64State_static))));
byte[] priExponent = key.getPrivateExponent().toByteArray();
D.appendChild(result.createTextNode(new String(Base64.encode(priExponent, b64State_static))));
return result;
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public static byte[] stripLeadingZeros(byte[] input)
{
while (input[0] == (byte) 0)
{
input = Arrays.copyOfRange(input, 1, input.length);
}
return input;
}
public static void saveKey(File file, PublicKey key)
{
try
{
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(key.getEncoded());
FileOutputStream fos = new FileOutputStream(file);
fos.write(x509EncodedKeySpec.getEncoded());
fos.close();
}
catch(Exception e){}
}
public static void saveKey(File file, PrivateKey key)
{
try
{
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(key.getEncoded());
FileOutputStream fos = new FileOutputStream(file);
fos.write(pkcs8EncodedKeySpec.getEncoded());
fos.close();
}
catch(Exception e){}
}
public PublicKey openPublicKey(String path, String algorithm)
{
try
{
File filePublicKey = new File(path);
FileInputStream fis = new FileInputStream(path);
byte[] encodedPublicKey = new byte[(int) filePublicKey.length()];
fis.read(encodedPublicKey);
fis.close();
KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(encodedPublicKey);
return keyFactory.generatePublic(publicKeySpec);
}
catch(Exception e){}
return null;
}
public PrivateKey openPrivateKey(String path, String algorithm)
{
try
{
File filePrivateKey = new File(path);
FileInputStream fis = new FileInputStream(path);
byte[] encodedPrivateKey = new byte[(int) filePrivateKey.length()];
fis.read(encodedPrivateKey);
fis.close();
KeyFactory keyFactory = KeyFactory.getInstance(algorithm);//RSA
PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(encodedPrivateKey);
return keyFactory.generatePrivate(privateKeySpec);
}
catch(Exception e){}
return null;
}
public static RSAPublicKey fetchPublicKeyFromXML(Document xml)
{
try
{
Element root = XMLMaster.getRoot(xml);
String mud = XMLMaster.getTextContent(root, "Modulus", 0);
String pubE = XMLMaster.getNodeValue(root, "Exponent", 0);
return generatePublicKeyFromDotNet(mud, pubE);
}
catch (Throwable e)
{
//throw new RuntimeException("Err: can not fetch PublicKey. " + e.toString());
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "Err: can not fetch PublicKey. ", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public static RSAPrivateCrtKey fetchPrivateKeyFromXML(Document xml)
{
try
{
Element root = XMLMaster.getRoot(xml);
String mud = XMLMaster.getTextContent(root, "Modulus", 0);
String pubE = XMLMaster.getNodeValue(root, "Exponent", 0);
String priE = XMLMaster.getNodeValue(root, "D", 0);
String p = XMLMaster.getNodeValue(root, "P", 0);
String Q = XMLMaster.getNodeValue(root, "Q", 0);
String EP = XMLMaster.getNodeValue(root, "DP", 0);
String EQ = XMLMaster.getNodeValue(root, "DQ", 0);
String cof = XMLMaster.getNodeValue(root, "InverseQ", 0);
return generatePrivateKeyFromDotNet(mud, pubE, priE, p, Q, EP, EQ, cof);
}
catch (Throwable e)
{
throw new RuntimeException("Err: can not fetch PrivateKey. " + e.toString());
}
}
public static PrivateKey loadPrivateKey(String privateKeyB64)
{
try
{
byte[] buffer = Base64.decode(privateKeyB64, Base64.NO_WRAP);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePrivate(keySpec);
//Class c = Reflector.getClassByAddressName("com.android.org.conscrypt.OpenSSLRSAPrivateKey");
//RSAPrivateKeySpec privSpec = new RSAPrivateKeySpec(modules, d);
}
catch (Throwable e)
{
throw new RuntimeException("Err: can not load PrivateKey. " + e.toString());
}
}
public String convertCaseToString(BigInteger num)
{
return num.toString(16);
} // Use: convertCaseToString(rsa.getPublicModule())
}
Because you are working with encrypted data, it is unlikely you can convert that directly to a String (each byte may not correspond to a character store-able in a String) - therefore I'd expect bytesToString(encryptedBytes) to usually fail. Try converting the encrypted data to Base64 first then that will always be store-able in a String. You then simply do the reverse to decrypt:-
// to encrypt and get a String object
byte[] encode = Base64.encode(encryptedBytes, Base64.NO_PADDING|Base64.NO_WRAP);
String encryptedDataStr = new String(encode);
Then you can do stuff (like store) the encryptedDataStr or whaterver. Then later...
// to decrypt
byte[] encryptedBytes = Base64.decode(encryptedDataStr, Base64.NO_PADDING|Base64.NO_WRAP);
byte [] decryptedBytes = cipher1.doFinal(encryptedBytes);
Good luck!

DSA signature - java.security.SignatureException: invalid encoding for signature

I have problem with DSA signature. My DSA code:
public byte[] signing(String text, PrivateKey privatekey) throws Exception {
byte[] textByte = text.getBytes();
Signature sign = Signature.getInstance("DSA");
sign.initSign(privatekey);
sign.update(textByte);
return sign.sign();
}
public boolean verify(String text, byte[] signature, PublicKey publickey) throws Exception {
byte[] textByte = text.getBytes();
Signature sign = Signature.getInstance("DSA");
sign.initVerify(publickey);
sign.update(textByte);
return sign.verify(signature);
}
And I run it on button action:
private void jButton9ActionPerformed(java.awt.event.ActionEvent evt) {
String message = jTextArea1.getText();
try {
signed = dsa.signing(message, privKey);
} catch (Exception ex) {
Logger.getLogger(DSAFrame.class.getName()).log(Level.SEVERE, null, ex);
}
String signedString = new String(signed);
jTextArea2.setText(signedString);
}
private void jButton10ActionPerformed(java.awt.event.ActionEvent evt) {
String signedString = jTextArea1.getText();
signToVer = jTextArea2.getText().getBytes();
try {
boolean correct = dsa.verify(signedString, signToVer, pubKey);
if(correct == true) {
JOptionPane.showMessageDialog(this, "Podpis poprawny", "Sukces", JOptionPane.INFORMATION_MESSAGE);
} else {
JOptionPane.showMessageDialog(this, "Podpis niepoprawny", "Błąd", JOptionPane.ERROR_MESSAGE);
}
} catch (Exception ex) {
Logger.getLogger(DSAFrame.class.getName()).log(Level.SEVERE, null, ex);
}
}
When I want verify signature, it throw me an java.security.SignatureException: invalid encoding for signature. I think, it's a problem with conversion string to byte array and back. But I don't know how to make it work.

Categories