Sawtooth Invalid Batch or Signature - java

I have started playing atound with Hyperledger Sawtooth recently, and having trouble to submit transactions on java, while python code seems okay.
I have prepared the python code based on the api docs here and then tried to write one in java as well. Below is the code in java
import com.google.protobuf.ByteString;
import com.mashape.unirest.http.Unirest;
import sawtooth.sdk.processor.Utils;
import sawtooth.sdk.protobuf.*;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.Signature;
import java.security.spec.ECGenParameterSpec;
public class BatchSender {
public static void main(String[] args) throws Exception{
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
ECGenParameterSpec parameterSpec = new ECGenParameterSpec("secp256k1");
keyPairGenerator.initialize(parameterSpec);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
Signature ecdsaSign = Signature.getInstance("SHA256withECDSA");
ecdsaSign.initSign(keyPair.getPrivate());
byte[] publicKeyBytes = keyPair.getPublic().getEncoded();
String publicKeyHex = Utils.hash512(publicKeyBytes);
ByteString publicKeyByteString = ByteString.copyFrom(new String(publicKeyBytes),"UTF-8");
String payload = "{'key':1, 'value':'value comes here'}";
String payloadBytes = Utils.hash512(payload.getBytes());
ByteString payloadByteString = ByteString.copyFrom(payload.getBytes());
TransactionHeader txnHeader = TransactionHeader.newBuilder().
setBatcherPubkeyBytes(publicKeyByteString).
setFamilyName("plain_info").
setFamilyVersion("1.0").
addInputs("1cf1266e282c41be5e4254d8820772c5518a2c5a8c0c7f7eda19594a7eb539453e1ed7").
setNonce("1").
addOutputs("1cf1266e282c41be5e4254d8820772c5518a2c5a8c0c7f7eda19594a7eb539453e1ed7").
setPayloadEncoding("application/json").
setPayloadSha512(payloadBytes).
setSignerPubkey(publicKeyHex).build();
ByteString txnHeaderBytes = txnHeader.toByteString();
ecdsaSign.update(txnHeaderBytes.toByteArray());
byte[] txnHeaderSignature = ecdsaSign.sign();
Transaction txn = Transaction.newBuilder().setHeader(txnHeaderBytes).setPayload(payloadByteString).setHeaderSignature(Utils.hash512(txnHeaderSignature)).build();
BatchHeader batchHeader = BatchHeader.newBuilder().setSignerPubkey(publicKeyHex).addTransactionIds(txn.getHeaderSignature()).build();
ByteString batchHeaderBytes = batchHeader.toByteString();
ecdsaSign.update(batchHeaderBytes.toByteArray());
byte[] batchHeaderSignature = ecdsaSign.sign();
Batch batch = Batch.newBuilder().setHeader(batchHeaderBytes).setHeaderSignature(Utils.hash512(batchHeaderSignature)).addTransactions(txn).build();
BatchList batchList = BatchList.newBuilder().addBatches( batch).build();
ByteString batchBytes = batchList.toByteString();
String serverResponse = Unirest.post("http://rest-api:8080/batches").header("Content-Type","application/octet-stream").body(batchBytes.toByteArray()).asString().getBody();
System.out.println(serverResponse);
}
}
Once I run it, I am getting
{
"error": {
"code": 30,
"message": "The submitted BatchList was rejected by the validator. It was poorly formed, or has an invalid signature.",
"title": "Submitted Batches Invalid"
}
}
On the dockers logs, I can see
sawtooth-validator-default | [2017-11-21 08:20:09.842 DEBUG interconnect] ServerThread receiving CLIENT_BATCH_SUBMIT_REQUEST message: 1242 bytes
sawtooth-validator-default | [2017-11-21 08:20:09.844 DEBUG signature_verifier] batch failed signature validation: 30a2f4a24be3e624f5a35b17cb505b65cb8dd41600545c6dcfac7534205091552e171082922d4eb71f1bb186fe49163f349c604b631f64fa8f1cfea1c8bb2818
sawtooth-validator-default | [2017-11-21 08:20:09.844 DEBUG interconnect] ServerThread sending CLIENT_BATCH_SUBMIT_RESPONSE to b'50b094689ac14b39'
I have checked the key sizes and verify the signature, and it seems all ok, however, i couldnt find why the batch is rejected...
Anyone had similar error response from sawtooth before? is it the batch format or still signature issue for the code above?

The problem is in setting the batch header signature and the transaction header signature. Those should not have the sha-512 hash taken of them. Those bytes should be encoded as hex strings.
Using the apache-commons-codec library that can be done as:
import org.apache.commons.codec.binary.Hex;
Transaction txn = Transaction.newBuilder()
.setHeader(txnHeaderBytes)
.setPayload(payloadByteString)
.setHeaderSignature(Hex.encodeHexString(txnHeaderSignature))
.build();
The Utils.sha512 should only be used on the payload bytes.

The Sawtooth Java SDK comes with a Signing class that can be helpful in
generating private/public key pairs and signing messages.
I have modified your code to use the specified class and included the changes from Boyd Johnson's answer for a working example (this is using Sawtooth Java SDK version 1.0):
import com.google.protobuf.ByteString;
import com.mashape.unirest.http.Unirest;
import com.mashape.unirest.http.exceptions.UnirestException;
import org.bitcoinj.core.ECKey;
import sawtooth.sdk.client.Signing;
import sawtooth.sdk.processor.Utils;
import sawtooth.sdk.protobuf.Batch;
import sawtooth.sdk.protobuf.BatchHeader;
import sawtooth.sdk.protobuf.BatchList;
import sawtooth.sdk.protobuf.Transaction;
import sawtooth.sdk.protobuf.TransactionHeader;
import java.security.SecureRandom;
public class BatchSender {
public static void main(String []args) throws UnirestException {
ECKey privateKey = Signing.generatePrivateKey(new SecureRandom());
String publicKey = Signing.getPublicKey(privateKey);
ByteString publicKeyByteString = ByteString.copyFromUtf8(publicKey);
String payload = "{'key':1, 'value':'value comes here'}";
String payloadBytes = Utils.hash512(payload.getBytes());
ByteString payloadByteString = ByteString.copyFrom(payload.getBytes());
TransactionHeader txnHeader = TransactionHeader.newBuilder()
.setBatcherPublicKeyBytes(publicKeyByteString)
.setSignerPublicKeyBytes(publicKeyByteString)
.setFamilyName("plain_info")
.setFamilyVersion("1.0")
.addInputs("1cf1266e282c41be5e4254d8820772c5518a2c5a8c0c7f7eda19594a7eb539453e1ed7")
.setNonce("1")
.addOutputs("1cf1266e282c41be5e4254d8820772c5518a2c5a8c0c7f7eda19594a7eb539453e1ed7")
.setPayloadSha512(payloadBytes)
.setSignerPublicKey(publicKey)
.build();
ByteString txnHeaderBytes = txnHeader.toByteString();
String txnHeaderSignature = Signing.sign(privateKey, txnHeaderBytes.toByteArray());
Transaction txn = Transaction.newBuilder()
.setHeader(txnHeaderBytes)
.setPayload(payloadByteString)
.setHeaderSignature(txnHeaderSignature)
.build();
BatchHeader batchHeader = BatchHeader.newBuilder()
.setSignerPublicKey(publicKey)
.addTransactionIds(txn.getHeaderSignature())
.build();
ByteString batchHeaderBytes = batchHeader.toByteString();
String batchHeaderSignature = Signing.sign(privateKey, batchHeaderBytes.toByteArray());
Batch batch = Batch.newBuilder()
.setHeader(batchHeaderBytes)
.setHeaderSignature(batchHeaderSignature)
.addTransactions(txn)
.build();
BatchList batchList = BatchList.newBuilder()
.addBatches(batch)
.build();
ByteString batchBytes = batchList.toByteString();
String serverResponse = Unirest.post("http://localhost:8008/batches")
.header("Content-Type","application/octet-stream")
.body(batchBytes.toByteArray())
.asString()
.getBody();
System.out.println(serverResponse);
}
}

I've just have the same issue. In my case the problem was in setting payload data.
Be sure that:
You made a sha512 hash of your PayloadByteArray and pass it to TransactionHeader creation
You pass PayloadByteArray to transaction creation.
So:
PayloadByteArray -> Transaction creation
sha512 Hash of PayloadByteArray -> TransactionHeader creation

Related

A java server use SHA256WithRSA to sign message, but python can not verify

Here is the code, the second (message, signature and public key) works fine on Java, can verify the message. But when I am using python, it will failed.
If am signed the message and the code will verify the message correctly.
Would some one help me to check the problem? Thank you.
# -*- coding:utf-8 -*-
from Crypto.PublicKey import RSA
from Crypto.Hash import SHA256
from Crypto.Signature import PKCS1_v1_5
from base64 import b64decode, b64encode
public_key = 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALyJy3rlD9EtWqVBzSIYxRRuFWRVn3juht2nupDCBSsWi7uKaRu3W0gn5y6aCacArtCkrf0EehwYRm0A4iHf8rkCAwEAAQ=='
private_key = 'MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAvInLeuUP0S1apUHNIhjFFG4VZFWfeO6G3ae6kMIFKxaLu4ppG7dbSCfnLpoJpwCu0KSt/QR6HBhGbQDiId/yuQIDAQABAkEAqm/y15UtOE7Ey/HxLCqyNqbRhdN1h5AxsT0IhgYvP+PhWGc3hRElMwNCdiNaJBh04R1iK6wmKoi3DSjkdU6IAQIhAPRL9khAdPMxjy5tpswNWeaDjNJrlUKEnItQUkoHqve5AiEAxZIDz235HcUgLg9ApYK4spOpzLDGCCgfO3FxmrUEUwECIEaLjQIOQvdbT1p75Ze1H0nWoRq+YGrF+qKsPicMkc1ZAiARlNTR+K9afthGQQU3tVJKUemiVXjJ8QgWehnp8oHYAQIhANsC2fEVjWv94Oy2c8I9qhuX+yfNtvZ2m+Kmf2o4JFrR'
bank_response_data = """{"head":{"vernbr":"1.0","mchnbr":"BILL0003","mchtyp":"BILLTYP","trscod":"BILL001","msgidc":"201805011230500001","sigtim":"20190307115511","sigalg":"SHA256WithRSA","retcod":"F","retmsg":"GWB2B006 源IP地址不在商户IP白名单中;商户编号:BILL0003;IP地址:123.139.40.150"}}"""
bank_response_signature = """uZl0/5D694GnAd/G9OPRs9BSd9fb0fZGXSGThBtgLnKi+CDQAdasOX05mKazXZki0blXxApGYRAWa/kOrf+Wl0USfklx0G5w/eGERfMdRWpvtV3S2MBCH/H/0T81nKGgn8svkT/Trj7+Mc+e654Jn8IijGyV9m8Ak92hG2bLtbc="""
bank_public_key = """MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDZs4l8Ez3F4MG0kF7RRSL+pn8MmxVE3nfdXzjx6d3rH8IfDbNvNRLS0X0b5iJnPyFO8sbbUo1Im4zX0M8XA0xnnviGyn5E6occiyUXJRgokphWb5BwaYdVhnLldctdimHoJTk3NFEQFav3guygR54i3tymrDc8lWtuG8EczVu8FwIDAQAB"""
def sign():
key_bytes = bytes(private_key, encoding="utf-8")
key_bytes = b64decode(key_bytes)
key = RSA.importKey(key_bytes)
hash_value = SHA256.new(bytes(bank_response_data, encoding="utf-8"))
signer = PKCS1_v1_5.new(key)
signature = signer.sign(hash_value)
return b64encode(signature)
def verify(data, signature, the_pub_key):
print(signature)
key_bytes = bytes(the_pub_key, encoding="utf-8")
key_bytes = b64decode(key_bytes)
key = RSA.importKey(key_bytes)
hash_value = SHA256.new(bytes(data, encoding="utf-8"))
verifier = PKCS1_v1_5.new(key)
if verifier.verify(hash_value, b64decode(signature)):
print("The signature is authentic.")
else:
print("The signature is not authentic.")
verify(bank_response_data, sign(), public_key)
verify(bank_response_data, bank_response_signature.encode('utf-8'),
bank_public_key)
# -*- coding:utf-8 -*-
from Cryptodome.Signature import PKCS1_v1_5 # pip install pycryptodomex
from Cryptodome.Hash import SHA256
from Cryptodome.PublicKey import RSA
from base64 import decodebytes, encodebytes
public_key = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALyJy3rlD9EtWqVBzSIYxRRuFWRVn3juht2nupDCBSsWi7uKaRu3W0gn5y6aCacArtCkrf0EehwYRm0A4iHf8rkCAwEAAQ=="
private_key = "MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAvInLeuUP0S1apUHNIhjFFG4VZFWfeO6G3ae6kMIFKxaLu4ppG7dbSCfnLpoJpwCu0KSt/QR6HBhGbQDiId/yuQIDAQABAkEAqm/y15UtOE7Ey/HxLCqyNqbRhdN1h5AxsT0IhgYvP+PhWGc3hRElMwNCdiNaJBh04R1iK6wmKoi3DSjkdU6IAQIhAPRL9khAdPMxjy5tpswNWeaDjNJrlUKEnItQUkoHqve5AiEAxZIDz235HcUgLg9ApYK4spOpzLDGCCgfO3FxmrUEUwECIEaLjQIOQvdbT1p75Ze1H0nWoRq+YGrF+qKsPicMkc1ZAiARlNTR+K9afthGQQU3tVJKUemiVXjJ8QgWehnp8oHYAQIhANsC2fEVjWv94Oy2c8I9qhuX+yfNtvZ2m+Kmf2o4JFrR"
bank_response_data = """{"head":{"vernbr":"1.0","mchnbr":"BILL0003","mchtyp":"BILLTYP","trscod":"BILL001","msgidc":"201805011230500001","sigtim":"20190307115511","sigalg":"SHA256WithRSA","retcod":"F","retmsg":"GWB2B006 源IP地址不在商户IP白名单中;商户编号:BILL0003;IP地址:123.139.40.150"}}"""
bank_response_signature = """uZl0/5D694GnAd/G9OPRs9BSd9fb0fZGXSGThBtgLnKi+CDQAdasOX05mKazXZki0blXxApGYRAWa/kOrf+Wl0USfklx0G5w/eGERfMdRWpvtV3S2MBCH/H/0T81nKGgn8svkT/Trj7+Mc+e654Jn8IijGyV9m8Ak92hG2bLtbc="""
bank_public_key = """MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDZs4l8Ez3F4MG0kF7RRSL+pn8MmxVE3nfdXzjx6d3rH8IfDbNvNRLS0X0b5iJnPyFO8sbbUo1Im4zX0M8XA0xnnviGyn5E6occiyUXJRgokphWb5BwaYdVhnLldctdimHoJTk3NFEQFav3guygR54i3tymrDc8lWtuG8EczVu8FwIDAQAB"""
def sign(private_key=private_key, raw_string=bank_response_data):
private_key = RSA.importKey(decodebytes(private_key.encode()))
signer = PKCS1_v1_5.new(private_key)
signature = signer.sign(SHA256.new(raw_string.encode()))
return encodebytes(signature).decode().replace("\n", "")
def verify(data, signature, public_key):
print(signature)
key = RSA.importKey(decodebytes(public_key.encode()))
hash_value = SHA256.new(data.encode())
verifier = PKCS1_v1_5.new(key)
if verifier.verify(hash_value, decodebytes(signature.encode())):
print("The signature is authentic.")
else:
print("The signature is not authentic.")
verify(bank_response_data, sign(), public_key)
verify(bank_response_data, bank_response_signature, bank_public_key)
Below is the java code, it works fine with the same signature and public key.
import org.apache.commons.codec.digest.DigestUtils;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
public class MyTest {
public static final String KEY_ALGORITHM = "RSA";
public static final String SIGNATURE_ALGORITHM = "SHA256WithRSA";
public static void main(String[] args) {
String data = "{\"head\":{\"vernbr\":\"1.0\",\"mchnbr\":\"BILL0003\",\"mchtyp\":\"BILLTYP\",\"trscod\":\"BILL001\",\"msgidc\":\"201805011230500001\",\"sigtim\":\"20190307115511\",\"sigalg\":\"SHA256WithRSA\",\"retcod\":\"F\",\"retmsg\":\"GWB2B006 源IP地址不在商户IP白名单中;商户编号:BILL0003;IP地址:123.139.40.150\"}}";
String signature = "dnAFU2e5zFb8rJ1mXDNk5AG9UyujVIUArkBjb1Nonf7iMhZwHfHRO633eW5n7uELFnyJZk6Go2D6ovp4jEnIoA==";
String cmbcRespSignature = "uZl0/5D694GnAd/G9OPRs9BSd9fb0fZGXSGThBtgLnKi+CDQAdasOX05mKazXZki0blXxApGYRAWa/kOrf+Wl0USfklx0G5w/eGERfMdRWpvtV3S2MBCH/H/0T81nKGgn8svkT/Trj7+Mc+e654Jn8IijGyV9m8Ak92hG2bLtbc=";
String cmbcPublicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDZs4l8Ez3F4MG0kF7RRSL+pn8MmxVE3nfdXzjx6d3rH8IfDbNvNRLS0X0b5iJnPyFO8sbbUo1Im4zX0M8XA0xnnviGyn5E6occiyUXJRgokphWb5BwaYdVhnLldctdimHoJTk3NFEQFav3guygR54i3tymrDc8lWtuG8EczVu8FwIDAQAB";
try {
boolean verify = verify(DigestUtils.sha256(data), cmbcPublicKey, cmbcRespSignature);
if (verify) {
}
} catch (Exception e) {
}
}
public static boolean verify(byte[] data, String publicKey, String sign) throws Exception {
final Base64.Decoder decoder = Base64.getDecoder();
final byte[] keyBytes = publicKey.getBytes("UTF-8");
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decoder.decode(keyBytes));
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
PublicKey pubKey = keyFactory.generatePublic(keySpec);
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initVerify(pubKey);
signature.update(data);
return signature.verify(decoder.decode(sign));
}
}
Finally, I get the answer.
In java
DigestUtils.sha256(data) did hash,
SHA256WithRSA algorithm will do hash
So what I should do is hash 2 times in my python code

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.

JBenchX eclipse very slow

I am writing a JBenchX method that calculates a keys of CMSS signature using flexiprovider. I want to get timings for my method createKeys, but that is very very slow. Without annnotation #Bench that is too fast < 1 sec. Could you help to understand What's happen here?
import de.flexiprovider.api.exceptions.NoSuchAlgorithmException;
import de.flexiprovider.api.keys.KeyPair;
import de.flexiprovider.api.keys.KeyPairGenerator;
import org.jbenchx.annotations.Bench;
import org.jbenchx.annotations.ForEachInt;
import org.jbenchx.annotations.ForEachString;
import org.jbenchx.annotations.SingleRun;
public class CMSSTest {
#Bench
public Object createKeys(#ForEachString({ "CMSSwithSHA1andWinternitzOTS_1" }) String cmss) throws NoSuchAlgorithmException {
Security.addProvider(new FlexiPQCProvider());
//byte[] signatureBytes = null;
KeyPairGenerator kpg = (CMSSKeyPairGenerator) Registry
.getKeyPairGenerator(cmss);
KeyPair keyPair = kpg.genKeyPair();
}
}
The actual output is and is active yet.
Initializing Benchmarking Framework...
Running on Linux Linux
Max heap = 1345847296 System Benchmark = 11,8ns
Performing 1 benchmarking tasks..
[0] CMSSTest.createObjectArray(CMSSwithSHA1andWinternitzOTS_1)!*!**!!!******!!******!****!****!!******!!!!*******!******!****!*********************************
The problem seems to be that Registry.getKeyPairGenerator creates a new KeyPairGenerator which is initialized using a 'true' random seed. For this, the system potentially has to wait for enough entropy to be available. Therefore, you should not do this as part of the code that you want to benchmark.
Try something like this:
import java.security.Security;
import org.jbenchx.annotations.Bench;
import org.jbenchx.annotations.ForEachString;
import de.flexiprovider.api.Registry;
import de.flexiprovider.api.exceptions.NoSuchAlgorithmException;
import de.flexiprovider.api.keys.KeyPair;
import de.flexiprovider.api.keys.KeyPairGenerator;
import de.flexiprovider.pqc.FlexiPQCProvider;
public class CMSSTest {
static {
Security.addProvider(new FlexiPQCProvider());
}
private final KeyPairGenerator kpg;
public CMSSTest(#ForEachString({"CMSSwithSHA1andWinternitzOTS_1"}) String cmss) throws NoSuchAlgorithmException {
this.kpg = Registry.getKeyPairGenerator(cmss);
}
#Bench
public Object createKeys() {
KeyPair keyPair = kpg.genKeyPair();
return keyPair;
}
}

Sign data using PKCS #7 in JAVA

I want to sign a text file (may be a .exe file or something else in the future)
using PKCS#7 and verify the signature using Java.
What do I need to know?
Where will I find an API (.jar and documentation)?
What are the steps I need to follow in order to sign data and verify the data?
Please provide me code snippet if possible.
I reckon you need the following 2 Bouncy Castle jars to generate the PKCS7 digital signature:
bcprov-jdk15on-147.jar (for JDK 1.5 - JDK 1.7)
bcmail-jdk15on-147.jar (for JDK 1.5 - JDK 1.7)
You can download the Bouncy Castle jars from here.
You need to setup your keystore with the public & private key pair.
You need only the private key to generate the digital signature & the public key to verify it.
Here's how you'd pkcs7 sign content (Exception handling omitted for brevity) :
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import org.bouncycastle.cert.jcajce.JcaCertStore;
import org.bouncycastle.cms.CMSProcessableByteArray;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.CMSSignedDataGenerator;
import org.bouncycastle.cms.CMSTypedData;
import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
import org.bouncycastle.util.Store;
import org.bouncycastle.util.encoders.Base64;
public final class PKCS7Signer {
private static final String PATH_TO_KEYSTORE = "/path/to/keyStore";
private static final String KEY_ALIAS_IN_KEYSTORE = "My_Private_Key";
private static final String KEYSTORE_PASSWORD = "MyPassword";
private static final String SIGNATUREALGO = "SHA1withRSA";
public PKCS7Signer() {
}
KeyStore loadKeyStore() throws Exception {
KeyStore keystore = KeyStore.getInstance("JKS");
InputStream is = new FileInputStream(PATH_TO_KEYSTORE);
keystore.load(is, KEYSTORE_PASSWORD.toCharArray());
return keystore;
}
CMSSignedDataGenerator setUpProvider(final KeyStore keystore) throws Exception {
Security.addProvider(new BouncyCastleProvider());
Certificate[] certchain = (Certificate[]) keystore.getCertificateChain(KEY_ALIAS_IN_KEYSTORE);
final List<Certificate> certlist = new ArrayList<Certificate>();
for (int i = 0, length = certchain == null ? 0 : certchain.length; i < length; i++) {
certlist.add(certchain[i]);
}
Store certstore = new JcaCertStore(certlist);
Certificate cert = keystore.getCertificate(KEY_ALIAS_IN_KEYSTORE);
ContentSigner signer = new JcaContentSignerBuilder(SIGNATUREALGO).setProvider("BC").
build((PrivateKey) (keystore.getKey(KEY_ALIAS_IN_KEYSTORE, KEYSTORE_PASSWORD.toCharArray())));
CMSSignedDataGenerator generator = new CMSSignedDataGenerator();
generator.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider("BC").
build()).build(signer, (X509Certificate) cert));
generator.addCertificates(certstore);
return generator;
}
byte[] signPkcs7(final byte[] content, final CMSSignedDataGenerator generator) throws Exception {
CMSTypedData cmsdata = new CMSProcessableByteArray(content);
CMSSignedData signeddata = generator.generate(cmsdata, true);
return signeddata.getEncoded();
}
public static void main(String[] args) throws Exception {
PKCS7Signer signer = new PKCS7Signer();
KeyStore keyStore = signer.loadKeyStore();
CMSSignedDataGenerator signatureGenerator = signer.setUpProvider(keyStore);
String content = "some bytes to be signed";
byte[] signedBytes = signer.signPkcs7(content.getBytes("UTF-8"), signatureGenerator);
System.out.println("Signed Encoded Bytes: " + new String(Base64.encode(signedBytes)));
}
}
PKCS#7 is known as CMS now (Cryptographic Message Syntax), and you will need the Bouncy Castle PKIX libraries to create one. It has ample documentation and a well established mailing list.
I won't supply code snippet, it is against house rules. Try yourself first.

EC2 Windows - Get Administrator Password

Currently, the only way I know to retrieve the administrator password from a newly created EC2 windows instance is through the AWS management console. This is fine, but I need to know how to accomplish this via the Java API - I can't seem to find anything on the subject. Also, once obtained, how do I modify the password using the same API?
The EC2 API has a call "GetPasswordData" which you can use to retrieve an encrypted block of data containing the Administrator password. To decrypt it, you need 2 things:
First, the private key. This is the private half of the keypair you used to instantiate the instance. A complication is that normally Amazon uses keys in PEM format ("-----BEGIN"...) but the Java Crypto API wants keys in DER format. You can do the conversion yourself - strip off the -----BEGIN and -----END lines, take the block of text in the middle and base64-decode it.
Second, the encryption parameters. The data is encrypted with RSA, with PKCS1 padding – so the magic invocation to give to JCE is: Cipher.getInstance("RSA/NONE/PKCS1Padding")
Here's a full example (that relies on BouncyCastle, but could be modified to use a different crypto engine)
package uk.co.frontiertown;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.ec2.AmazonEC2Client;
import com.amazonaws.services.ec2.model.GetPasswordDataRequest;
import com.amazonaws.services.ec2.model.GetPasswordDataResult;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Base64;
import javax.crypto.Cipher;
import java.nio.charset.Charset;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.Security;
import java.security.spec.PKCS8EncodedKeySpec;
public class GetEc2WindowsAdministratorPassword {
private static final String ACCESS_KEY = "xxxxxxxxxxxxxxxxxxxx";
private static final String SECRET_KEY = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
private static final String PRIVATE_KEY_MATERIAL = "-----BEGIN RSA PRIVATE KEY-----\n" +
"MIIEowIBAAKCAQEAjdD54kJ88GxkeRc96EQPL4h8c/7V2Q2QY5VUiJ+EblEdcVnADRa12qkohT4I\n" +
// several more lines of key data
"srz+xXTvbjIJ6RL/FDqF8lvWEvb8uSC7GeCMHTznkicwUs0WiFax2AcK3xjgtgQXMgoP\n" +
"-----END RSA PRIVATE KEY-----\n";
public static void main(String[] args) throws GeneralSecurityException, InterruptedException {
Security.addProvider(new BouncyCastleProvider());
String password = getPassword(ACCESS_KEY, SECRET_KEY, "i-XXXXXXXX", PRIVATE_KEY_MATERIAL);
System.out.println(password);
}
private static String getPassword(String accessKey, String secretKey, String instanceId, String privateKeyMaterial) throws GeneralSecurityException, InterruptedException {
// Convert the private key in PEM format to DER format, which JCE can understand
privateKeyMaterial = privateKeyMaterial.replace("-----BEGIN RSA PRIVATE KEY-----\n", "");
privateKeyMaterial = privateKeyMaterial.replace("-----END RSA PRIVATE KEY-----", "");
byte[] der = Base64.decode(privateKeyMaterial);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(der);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
// Get the encrypted password data from EC2
AWSCredentials awsCredentials = new BasicAWSCredentials(accessKey, secretKey);
AmazonEC2Client client = new AmazonEC2Client(awsCredentials);
GetPasswordDataRequest getPasswordDataRequest = new GetPasswordDataRequest().withInstanceId(instanceId);
GetPasswordDataResult getPasswordDataResult = client.getPasswordData(getPasswordDataRequest);
String passwordData = getPasswordDataResult.getPasswordData();
while (passwordData == null || passwordData.isEmpty()) {
System.out.println("No password data - probably not generated yet - waiting and retrying");
Thread.sleep(10000);
getPasswordDataResult = client.getPasswordData(getPasswordDataRequest);
passwordData = getPasswordDataResult.getPasswordData();
}
// Decrypt the password
Cipher cipher = Cipher.getInstance("RSA/NONE/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] cipherText = Base64.decode(passwordData);
byte[] plainText = cipher.doFinal(cipherText);
String password = new String(plainText, Charset.forName("ASCII"));
return password;
}
}
ObDisclosure: I originally answered this on a blog posting at http://www.frontiertown.co.uk/2012/03/java-administrator-password-windows-ec2-instance/
You can create an instance, set the password and then turn it back into an image. Effectively setting a default password for each instance you create. Wouldn't this be simpler?
Looks like you are looking for the following parts of the API: GetPasswordDataRequest and GetPasswordDataResult
You can also create a Image with default user name and Password setup on that Image.And then launch all instances with that image id..so that you dont need to create and retrieve password evry time..just launch your instance rdp that launched instance with definde credntials in Image. I am doing same.And its perfectly working for me.

Categories

Resources