Strange SHA256 Behavior - java

As can be seen from the screenshot(https://jwt.io/) which is the expected signature, I am getting wrong java code. I am missing something very obvious wrong with code?
package com.company;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
public class Main {
public static void main(String[] args) throws InvalidKeyException, NoSuchAlgorithmException {
final Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec("qwertyuiopasdfghjklzxcvbnm123456".getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
String sourcString = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE2MjM5NTk5NDEsImV4cCI6MTY1NTQ5NTk0MSwiYXVkIjoid3d3LmV4YW1wbGUuY29tIiwic3ViIjoianJvY2tldEBleGFtcGxlLmNvbSIsIkdpdmVuTmFtZSI6IkpvaG5ueSIsIlN1cm5hbWUiOiJSb2NrZXQiLCJFbWFpbCI6Impyb2NrZXRAZXhhbXBsZS5jb20ifQ";
byte[] signatureBytes = mac.doFinal(sourcString.getBytes(StandardCharsets.UTF_8));
System.out.println("Signatured=" + Base64.getEncoder().withoutPadding().encodeToString(signatureBytes));
}
}
OUTPUT : Signatured=ZFrcK6AZzYCTs0ugepzcSFMxxuY5Fs0PtMXGDZtT3sA
http://tpcg.io/P0MtSDC3

Looks like you almost got it, since you provide the SecretKeySpec in clear text you don't have to check this check box ... or provide a clear text SecretKey that actually encodes to "qwertyuiopasdfghjklzxcvbnm123456".

Related

How to correctly generate a pair of SSH keys in java, that is compatible with OpenSSL

I'm trying to dynamically generate a pair of SSH keys in java, mimicking the behaviour of ssh-keygen. I intend to use those keys to communicate with an SSH server.
I have tried patching up and testing several pieces of code without success. The most recent piece of code I'm testing is this:
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
import org.bouncycastle.crypto.KeyGenerationParameters;
import org.bouncycastle.crypto.generators.Ed25519KeyPairGenerator;
import org.bouncycastle.crypto.util.OpenSSHPrivateKeyUtil;
import org.bouncycastle.crypto.util.OpenSSHPublicKeyUtil;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemWriter;
import org.junit.jupiter.api.Test;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.security.SecureRandom;
import java.security.Security;
public class GenKeysTest {
#Test
void testCase1() throws IOException {
Security.addProvider(new BouncyCastleProvider());
AsymmetricCipherKeyPairGenerator gen = new Ed25519KeyPairGenerator();
gen.init(new KeyGenerationParameters(new SecureRandom(), 255));
AsymmetricCipherKeyPair keyPair = gen.generateKeyPair();
byte[] priBytes = OpenSSHPrivateKeyUtil.encodePrivateKey(keyPair.getPrivate());
write(priBytes, "ed25519", "OPENSSH PRIVATE KEY");
byte[] pubBytes = OpenSSHPublicKeyUtil.encodePublicKey(keyPair.getPublic());
write(pubBytes, "ed25519.pub", "OPENSSH PUBLIC KEY");
}
public void write(byte[] bytes, String fileName, String type) throws IOException {
try (FileOutputStream out = new FileOutputStream(fileName)) {
try (PemWriter w = new PemWriter(new OutputStreamWriter(out))) {
w.writeObject(new PemObject(type, bytes));
}
}
}
}
I'm using the following dependencies:
dependencies {
implementation 'org.bouncycastle:bcprov-jdk15on:1.67'
implementation 'org.bouncycastle:bcpkix-jdk15on:1.67'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
}
And I'm using these command to test the resulting keys:
ssh-keygen -l -f ed25519
ssh-keygen -l -f ed25519.pub
As far as I read, those commands should output the same text line which should look like this:
256 SHA256:REDACTED user#domain.com (ED25519)
Instead the output I get from ssh-keygen is similar to this:
ed25519.pub is not a public key file.
It would be very nice if someone could point me what am I missing.

Problem with encryption/Decryption code written in Jmeter

I have written a code in beanshell for encryption and decryption in Jmeter but somehow its not working. I am getting error : In file: inline evaluation of: ``import java.security.InvalidAlgorithmParameterException; import java.security.In . . . '' Encountered "}" at line 19, column 82.
I have added the crypto jar in test plan but issue persists.
Attached is the code.
Working :
I am generating a random string(R1) and encryption it with a public key using RSA algo.
Using the key R1, I need to encrypt the request body using AES algo, CBC mode, PKCS7Padding.
package com.sample.feedbackrating;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;
import java.util.UUID;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class Crypto {
public static IvParameterSpec generateIv() {
byte[] iv = new byte[16];
return new IvParameterSpec(iv);
}
public static String encrypt(String algorithm, String input, String secretKey, IvParameterSpec iv) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException
{
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.ENCRYPT_MODE, new
SecretKeySpec(secretKey.getBytes(), "AES"), iv);
byte[] cipherText = cipher.doFinal(input.getBytes());
return Base64.getEncoder().encodeToString(cipherText);
}
public static String decrypt(String algorithm, String cipherText, String secretKey, IvParameterSpec iv) throws NoSuchPaddingException, NoSuchAlgorithmException,InvalidAlgorithmParameterException, InvalidKeyException,BadPaddingException, IllegalBlockSizeException
{
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(secretKey.getBytes(), "AES"), iv);
byte[] plainText = cipher.doFinal(Base64.getDecoder().decode(cipherText));
return new String(plainText);
}
public static String generateSecretKey() {
return UUID.randomUUID().toString().replace("-", "");
}
}
Encountered "}" is a syntax error so double check your Beanshell script for eventual missing semicolons or closing brackets or whatever. You can use online lint tool like this one to see where exactly the problem is
In general I cannot reproduce your issue:
So it's either a copy-paste issue or a Beanshell-related problem, be aware that starting from JMeter 3.1 you're supposed to use JSR223 Test Elements and Groovy language for scripting, especially for "heavy" tasks like cryptographic operations.

How to Encrypt data in ruby same as SecretKeySpec?

I am trying to encrypt a string in ruby using Cipher with AES algorithm. I have example written in Java. I have taken help from this example and written code in Java but not able to get the same output as in JAVA.
Following is the code written in java
import java.util.Base64;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.security.Key;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.util.Arrays;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class HelloWorld {
public static final String PHONENUMBER_PARAM = "phoneNumber";
public static final String PIN_PARAM ="pin";
public static final String MERCHANTID_PARAM = "merchantId";
public static void main(String args[]) throws Exception {
String phoneNumber ="+917738995286";
String pin ="5577";
String merchantId ="527425858";
String encodedKey ="vPDkdTDrcygLPROzd1829A==";
String payLoad = PHONENUMBER_PARAM + "=" + URLEncoder.encode(phoneNumber, "UTF-8")+ "&" + PIN_PARAM + "=" + URLEncoder.encode(pin, "UTF-8") ;
byte[] decodedKey = Base64.getDecoder().decode(encodedKey.getBytes());
Key encryptionKey = new SecretKeySpec(decodedKey, "AES");
byte[] utf8Bytes = payLoad.getBytes("utf-8");
byte[] encryptedBody = encrypt(encryptionKey, utf8Bytes);
String encryptedData = new String(Base64.getEncoder().encode(encryptedBody));
System.out.println("encryptedData:" + encryptedData);
}
private static byte[] encrypt(Key encryptionKey, byte[] data) throws Exception {
Cipher c = Cipher.getInstance("AES");
c.init(1, encryptionKey);
return c.doFinal(data);
}
}
Output of this code is
encryptedData:lE40HlECbxU/mWRivF/+Szm3PprMoLW+Y7x911GczunakbG8l+A2JVEEP8gTw6xy
I tried to write the same code in ruby. Ruby Code is:
payLoad = "phoneNumber=%2B917738995286&pin=5577"
encodedKey = "vPDkdTDrcygLPROzd1829A=="
decodedKey = Base64.decode64(encodedKey)
dKey = decodedKey.each_byte.map { |b| b.to_s(16) }.join
cipher = OpenSSL::Cipher.new('aes128').encrypt
encryptionKey = cipher.update(dKey)
encryptionKey<< cipher.final
utf8Bytes = payLoad.bytes
uKey = utf8Bytes.map { |b| b.to_s(16) }.join
scipher = OpenSSL::Cipher.new('aes128').encrypt
scipher.key = encryptionKey
encryptedBody = scipher.update(uKey)
encryptedBody<< scipher.final
encryptedData = Base64.encode64(encryptedBody)
Output of this code is
CqFmCKJ004PsoXi2tDCTBmx7/iTHVyDsFH9y8NWNrEP3k3bOQp7h8uyl/a7Z\nYi9ZmcXSspo6FCyCo6fJIwPohg==\n
Don't know where is the error. I have already worked for 2 days but not able to get any answer. Any help will be great. Thanks in advance.
The following version outputs the same result as your Java code:
# crypt.rb
require 'base64'
require 'openssl'
payLoad = "phoneNumber=%2B917738995286&pin=5577"
encodedKey = "vPDkdTDrcygLPROzd1829A=="
decodedKey = Base64.decode64(encodedKey)
scipher = OpenSSL::Cipher.new('aes-128-ecb').encrypt
scipher.key = decodedKey
encryptedBody = scipher.update(payLoad)
encryptedBody << scipher.final
encryptedData = Base64.encode64(encryptedBody)
puts encryptedData
$ ruby crypt.rb
# => lE40HlECbxU/mWRivF/+Szm3PprMoLW+Y7x911GczunakbG8l+A2JVEEP8gT
# w6xy
Notable differences from your ruby script version:
You must specify the cipher mode. The problem is that Java defaults to the ECB mode whereas ruby defaults to the CBC mode. By the way, the ECB mode is considered less-secure today and you actually should not use it.
In ruby, you tried to re-encrypt the Base64-decoded version of your encryption key, which is something you don't do in the Java version.
In ruby, there is no need to do the string to byte conversions, you can encrypt strings right away.
So, although the two scripts output the same encrypted data now, I would strongly consider changing the AES mode of operation, to actually stay secure.

Java, Illegal Access Error when accessing another class

I am trying to write a ssl decryption program. I found some old code from 2010 and have tried to get it to run. After finally being able to compile it I now get this error:
Exception in thread "main" java.lang.IllegalAccessError: tried to access class sun.security.ssl.CipherSuite from class sun.security.ssl.decrypt at sun.security.ssl.decrypt.main(decrypt.java:36)
which is the line where I call CipherSuite.valueOf(0x00, 0x2f); (deleted some comment lines that's why it might be another line number here)
Now I have read that it would probably be a problem with the method valueOf() being private. Since I am a newbie to java I don't know how to handle that, because the code I would need to change is in a jar. (Using openjdk-1.7)
On the other hand, it says here
that the method is just static. Also checking with .isAvailable() like recommended in the link above (at the .valueOf method) does not help.
Any suggestions?
Here is the code I got so far:
package sun.security.ssl;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.BadPaddingException;
import javax.crypto.SecretKey;
import javax.xml.bind.DatatypeConverter;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import sun.security.internal.spec.TlsKeyMaterialParameterSpec;
import sun.security.internal.spec.TlsKeyMaterialSpec;
import sun.security.ssl.CipherSuite.BulkCipher;
public class decrypt {
public static void main(String[] args) throws InvalidKeyException, NoSuchAlgorithmException {
byte[] clrnd = DatatypeConverter.parseHexBinary("be9b706c800f93526913732a356c7e7fe9383ace52f5ed120d38a81db07e903d");
byte[] srvrnd = DatatypeConverter.parseHexBinary("56af786428bc3e0c69ef2fdd9f6e3456ceae660a323d6109e9554b4af7fe6652");
ProtocolVersion pv = ProtocolVersion.valueOf(0x03, 0x03);
CipherSuite cipher_suite = CipherSuite.valueOf(0x00, 0x2f);
String KeyAlgo = cipher_suite.cipher.algorithm;
String Master_Key = "c55ca8dd56fa59b80b8ff01d9a1d4f04251aec41ab6340e8db118b3d4d2ef895cc51592f9bcd5dbde5eda9d5ad386f34";
byte[] master_secret = DatatypeConverter.parseBase64Binary(Master_Key);
byte[] client_app_data = DatatypeConverter.parseHexBinary("715e388b6ed9339faa6fc640f329c358");
SecretKey masterkey = new SecretKeySpec(master_secret, 0, master_secret.length, KeyAlgo);
//Calculate connection keys
BulkCipher cipher = cipher_suite.cipher;
int expandedKeySize = cipher_suite.exportable ? cipher.expandedKeySize : 0;
KeyGenerator kg = JsseJce.getKeyGenerator("SunTlsKeyMaterial");
int pv_major = pv.major;
int pv_minor = pv.minor;
try {
kg.init(new TlsKeyMaterialParameterSpec(masterkey, pv_major, pv_minor, clrnd, srvrnd, cipher.algorithm, cipher.keySize, expandedKeySize, cipher.ivSize, cipher_suite.macAlg.size, cipher_suite.prfAlg.getPRFHashAlg(), cipher_suite. prfAlg.getPRFHashLength(), cipher_suite.prfAlg.getPRFBlockSize()));
} catch (InvalidAlgorithmParameterException ex) {
Logger.getLogger(decrypt.class.getName()).log(Level.SEVERE, null, ex);
}
TlsKeyMaterialSpec keySpec = (TlsKeyMaterialSpec)kg.generateKey();
SecretKey clntWriteKey = keySpec.getClientCipherKey();
IvParameterSpec clntWriteIV = keySpec.getClientIv();
SecureRandom clientrandom = new SecureRandom(clrnd);
CipherBox svbox = cipher_suite.cipher.newCipher(pv, clntWriteKey, clntWriteIV, clientrandom, false);
try {
svbox.decrypt(client_app_data, 5, client_app_data.length-5, 0);
} catch (BadPaddingException ex) {
Logger.getLogger(decrypt.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println(svbox);
}
}
Thanks!
I guess because it uses the default access modifier.
Java Access Modifiers
The class sun.security.ssl.CipherSuite uses the default access modifier. This means that you can only access this class from the same package, which is not the case in your project.
CipherSuite class definition

Verifying signature of a file using the certificates available in store

I am totally new to security and signature verification and so far I couldn't find a place which explained the basics of signature verification. I need to verify the signature of a file by obtaining the public key from the appropriate certificate available from certificate store. the tutorial in Java (https://docs.oracle.com/javase/tutorial/security/apisign/versig.html) doesn't teach how to obtain a certificate from the trusted certificate store and verify using that. I went through Bouncy castle WIKI http://www.bouncycastle.org/wiki/display/JA1/BC+Version+2+APIs but its not really explanatory for a beginner. How do I do this? Given a signed file, how can I check for its public key from the certificate store and verify if its the right person who has sent the file? Please advice.
Because you did not provide what build management you use, I assume it will be Maven.
First, include BouncyCastle in your dependency
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.53</version>
</dependency>
After that, you need to make a util class that you will be using for sign or verify the certificate. Something like this:
package your.pack.location;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.bouncycastle.util.encoders.Base64;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
/**
* Author: harunalfat
*/
public class SignatureUtils {
private static final Logger log = LogManager.getLogger(SignatureUtils.class);
public static String sign(String plainText, PrivateKey privateKey) throws Exception {
byte[] data = plainText.getBytes("ISO-8859-1");
Signature signature = Signature.getInstance("SHA1WithRSA", "BC");
signature.initSign(privateKey);
signature.update(data);
return Base64.toBase64String(signature.sign());
}
public static boolean verify(String plainText, String signString, PublicKey publicKey) throws Exception{
byte[] data = plainText.getBytes("ISO-8859-1");
Signature signature = Signature.getInstance("SHA1WithRSA", "BC");
signature.initVerify(publicKey);
signature.update(data);
byte[] signByte = Base64.decode(signString);
return signature.verify(signByte);
}
private static PemObject getPemObjectFromResource(String fileLocation) throws IOException {
Resource resource = new ClassPathResource(fileLocation);
InputStream is = resource.getInputStream();
PemObject pemObject = new PemReader(new InputStreamReader( is )).readPemObject();
return pemObject;
}
private static X509EncodedKeySpec getPubKeySpec(String fileLocation) throws IOException, NoSuchAlgorithmException {
PemObject pemObject = getPemObjectFromResource(fileLocation);
byte[] data = pemObject.getContent();
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(data);
return keySpec;
}
private static PKCS8EncodedKeySpec getPriKeySpec(String fileLocation) throws IOException, NoSuchAlgorithmException {
PemObject pemObject = getPemObjectFromResource(fileLocation);
byte[] data = pemObject.getContent();
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(data);
return keySpec;
}
public static PublicKey getPublicKey(String fileLocation) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
KeyFactory kf = KeyFactory.getInstance("RSA");
KeySpec keySpec = getPubKeySpec(fileLocation);
return kf.generatePublic(keySpec);
}
public static PrivateKey getPrivateKey(String fileLocation) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
KeyFactory kf = KeyFactory.getInstance("RSA");
KeySpec keySpec = getPriKeySpec(fileLocation);
return kf.generatePrivate(keySpec);
}
}
And then you will use it like this
package your.another.pack;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.tomcat.util.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.Test;
import org.mockito.MockitoAnnotations;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import static org.junit.Assert.assertTrue;
/**
* Author: harunalfat
*/
public class SignatureUtilsTest {
private static final Logger log = LogManager.getLogger(SignatureUtilsTest.class);
private static final String PLAIN = "attack at dawn";
#Test
public void testSignAndVerify() throws Exception {
Security.addProvider(new BouncyCastleProvider()); // <-- IMPORTANT!!! This will add BouncyCastle as provider in Java Security
PrivateKey privateKey = SignatureUtils.getPrivateKey("key/private2.pem"); // This is located on src/main/resources/key/private2.pem
PublicKey publicKey = SignatureUtils.getPublicKey("key/public2.pem"); // This is located on src/main/resources/key/public2.pem
// In this example, I use junit test, so it will be on src/test/resources/...
log.info("Private Key : "+Base64.encodeBase64String(privateKey.getEncoded()));
log.info("Public Key : "+Base64.encodeBase64String(publicKey.getEncoded()));
String sign = SignatureUtils.sign(PLAIN, privateKey);
log.info("Plain String : "+PLAIN);
log.info("Sign : "+sign);
boolean result = SignatureUtils.verify(PLAIN,sign, publicKey);
log.info("Result : "+result);
assertTrue(result);
}
}
Of course, you can change the Signature instance with another Algorithm. In my case I use "SHA1WithRSA", but you get the point right?
With this, someone will encrypt their data using their private key, and send it to you. After that, you will verify the data using the public key they give.
In example, Bob send to you message about money amount he sent to you ($5000), and sign it using their private key, become encrypted. When the data arrived to you, you know Bob supposed to send $5000, then you verify the encrypted data with text $5000 and public key Bob share, but is it really $5000 OR does it comes from Bob?
If the data has been changed, OR when someday you ask for some Money to Bob, but the message tapped by someone else and s/he send you the amount message with private key other than Bob's, you will know.
Feel free to ask :)

Categories

Resources