It is possible to generate a valid legacy bitcoin key pair with the following code which is using bitcoinj master branch:
import org.bitcoinj.core.Address;
import org.bitcoinj.core.DumpedPrivateKey;
import org.bitcoinj.core.ECKey;
import org.bitcoinj.core.NetworkParameters;
public class GeneratePrivateKeyBulk {
public static void main(String[] args) {
ECKey key = new ECKey();
Address pubAddress = new Address(NetworkParameters.prodNet(), key.getPubKeyHash());
DumpedPrivateKey privKey = key.getPrivateKeyEncoded(NetworkParameters.prodNet());
System.out.println("Public address: " + pubAddress.toBase58() + "; Private key: " + privKey.toBase58());
}
}
This creates a usable legacy base58 encoded public address and private key e.g. like 1ERzRYYdbibaQt2kuNfgH8spuoqQxYkwQb, L3AuZ2vNt11ac2xSi6AYwzXyftqSVPcSuHNdTsSuRfknXvoRtWzF correspondingly.
The question is how can I do the same operation to obtain a segwit key pair?
I looked at the bitcoinj docs but could not find any API for generating addresses directly as segwit.
By looking at the tests and the segwit pull request I found that the following code (appended to the code above) would produce a segwit address (i.e. one that starts with 3, e.g. 31uLnxKteEYa2u1vgWyVPkTpVfUGduCV82)
Script script = ScriptBuilder.createP2SHOutputScript(1, Collections.singletonList(key));
Address segwitAddress = Address.fromP2SHScript(NetworkParameters.prodNet(), script);
System.out.println("Segwit address: " + segwitAddress.toBase58());
My understanding is that the code above is supposed to be used in a multisig scenario, therefore I am not sure if this is the correct way to derive a segwit address from a single private key. Is this the correct/reliable/safe code for generating a paper segwit wallet?
Also, is there a way to add BIP38 password protection to the private key using bitcoinj? The class BIP38PrivateKey only has methods for decrypting a BIP38 key from an existing base58 representation, but no methods for BIP38 password encryption.
Related
I have generated a private-public key pair using the web3j library.
ECKeyPair ecKeyPair = Keys.createEcKeyPair();
BigInteger publicKey = ecKeyPair.getPublicKey();
This returns an uncompressed form of the public key. I wanted to convert the same to a compressed format to generate the wallet using the below website.
https://lab.miguelmota.com/ethereum-public-key-to-address/example/
I know we can create the wallet directly using the Keypair, but I need this to work on the above website when I paste the public key.
I am using web3j version 5.0.0, and there is no built-in method to compress the public key.
Are there any other libraries or methods we can use to achieve the same
Try this for compressed public key - info from here
DeterministicSeed seed = new DeterministicSeed("some seed code here", null, "", 1409478661L);
DeterministicKeyChain chain = DeterministicKeyChain.builder().seed(seed).build();
DeterministicKey addrKey = chain.getKeyByPath(HDUtils.parsePath("M/44H/60H/0H/0/0"), true);
System.out.println("Address: " + Keys.getAddress(Sign.publicKeyFromPrivate(addrKey.getPrivKey()))); // mapper();
System.out.println("Uncompressed public key: " + Sign.publicKeyFromPrivate(addrKey.getPrivKey()).toString(16));
System.out.println("Compressed key: " + addrKey.getPublicKeyAsHex());
-- Output --
Address: 97f2582fec180600268ebae9a0052e676d876c27
Uncompressed public key: 37efe8e46dc39bee0f099871de99fe68a931730c02ef2918f832f30572b3f1a54f8d52fcaea129e31ac836063e2c432aac815cb86664165d1a226fe51a851d47
Compressed key: 0337efe8e46dc39bee0f099871de99fe68a931730c02ef2918f832f30572b3f1a5
Dependencies are as follows:
import org.bitcoinj.crypto.DeterministicKey;
import org.bitcoinj.crypto.HDUtils;
import org.bitcoinj.wallet.DeterministicKeyChain;
import org.bitcoinj.wallet.DeterministicSeed;
import org.bitcoinj.wallet.UnreadableWalletException;
import org.mapstruct.AfterMapping;
import org.web3j.crypto.ECKeyPair;
import org.web3j.crypto.Keys;
import org.web3j.crypto.Sign;
<dependency>
<groupId>org.web3j</groupId>
<artifactId>crypto</artifactId>
<version>3.3.1-android</version>
</dependency>
<dependency>
<groupId>org.bitcoinj</groupId>
<artifactId>bitcoinj-core</artifactId>
<version>0.16.2</version>
</dependency>
I am using the IAIK wrapper to send pkcs11 requests to my Bull HSM. My objective is to generate a consistent key (token = true). The problem is that I always have this error code:
Exception in thread "main" iaik.pkcs.pkcs11.wrapper.PKCS11Exception: CKR_ATTRIBUTE_READ_ONLY
I can't understand why it's read-only? To initialize my Session I do so (using the RW_SESSION option):
import iaik.pkcs.pkcs11.Mechanism;
import iaik.pkcs.pkcs11.Module;
import iaik.pkcs.pkcs11.Session;
import iaik.pkcs.pkcs11.Token;
import iaik.pkcs.pkcs11.TokenException;
import iaik.pkcs.pkcs11.objects.AESSecretKey;
import iaik.pkcs.pkcs11.wrapper.PKCS11Constants;
...
static String libP11 = "nethsm.dll";
static String hsmPassword = "123456";
static int hsmSlotId = 1;
private static void initHSM() throws IOException, TokenException{
Module module = Module.getInstance(libP11);
module.initialize(null);
Token token = module.getSlotList(Module.SlotRequirement.TOKEN_PRESENT)[hsmSlotId - 1].getToken();
session = token.openSession(Token.SessionType.SERIAL_SESSION, Token.SessionReadWriteBehavior.RW_SESSION, null,
null);
session.login(Session.UserType.USER, hsmPassword.toCharArray());
}
My function to generate the key is the following:
private static AESSecretKey generateAESKey(byte[] keyValue, String label, int keyLength, boolean token) throws TokenException {
Mechanism keyGenerationMechanism = Mechanism.get(PKCS11Constants.CKM_AES_KEY_GEN);
AESSecretKey secretKeyTemplate = new AESSecretKey();
secretKeyTemplate.getValueLen().setLongValue(new Long(keyLength));
secretKeyTemplate.getLabel().setCharArrayValue(label.toCharArray());
secretKeyTemplate.getToken().setBooleanValue(token);
secretKeyTemplate.getSensitive().setBooleanValue(Boolean.FALSE);
secretKeyTemplate.getExtractable().setBooleanValue(Boolean.TRUE);
secretKeyTemplate.getDerive().setBooleanValue(Boolean.TRUE);
secretKeyTemplate.getModifiable().setBooleanValue(Boolean.TRUE);
secretKeyTemplate.getEncrypt().setBooleanValue(Boolean.TRUE);
secretKeyTemplate.getDecrypt().setBooleanValue(Boolean.TRUE);
secretKeyTemplate.getUnwrap().setBooleanValue(Boolean.TRUE);
secretKeyTemplate.getWrap().setBooleanValue(Boolean.TRUE);
secretKeyTemplate.getSign().setBooleanValue(Boolean.TRUE);
secretKeyTemplate.getVerify().setBooleanValue(Boolean.TRUE);
secretKeyTemplate.getValue().setByteArrayValue(keyValue);
return (AESSecretKey) session.generateKey(keyGenerationMechanism, secretKeyTemplate);
}
Any solutions please?
It does not make sense to use:
secretKeyTemplate.getValue().setByteArrayValue(keyValue)
to set key value (CKA_VALUE in PKCS#11) while generating new key -- HSM will generate key value for you. Remove this line.
Note: If you want to create key with a given value try C_CreateObject (Session.createObject in IAIK Wrapper) instead -- but not all HSMs support this way. If you fail to create key with a known value using this method you will have to use C_UnwrapKey to import encrypted key value which usually works.
Good luck with your project!
I am creating a wallet from mnemonics,for ethereum i have used web3j library for generating mnemonics,address and its private key and now for bitcoin i want to use the same generated mnemonics to generate bitcoin address and its private key for bitcoin i am using Bitcoinj library but not able to get its address and key.
I also tried Walletappkit but its generating address without getting mnemonics so is there any way of using mnemonics in Walletappkit so i can get bitcoin address and sync the bitcoin chain for transactions.
Also is there any way of using walletappkit without syncing and gets bitcoin detail like its balance and transaction info.
Below is the code how I created ethereum wallet and its mnemonic key using web3j and bitcoinj.
val wallet = WalletUtils.generateBip39Wallet("", File(path))
val mnemonics = wallet.mnemonic
// bitcoinj
var seed = DeterministicSeed(wallet.mnemonic, null, "", 1409478661L)
val chain = DeterministicKeyChain.builder().seed(seed).build()
val keyPath = HDUtils.parsePath("M/44H/60H/0H/0/0")
val key = chain.getKeyByPath(keyPath, true)
val privKey = key.privKey
// Web3j
val credentials = Credentials.create(privKey.toString(16))
val eth_address = credentials.address
I'm not sure if I correctly understand what you want to do, but if you want to restore/create a Bitcoinj wallet from a mnemonic seed, then there's an official example for this here:
// Here we restore our wallet from a seed with no passphrase. Also have a look at the BackupToMnemonicSeed.java example that shows how to backup a wallet by creating a mnemonic sentence.
String seedCode = "yard impulse luxury drive today throw farm pepper survey wreck glass federal";
String passphrase = "";
Long creationtime = 1409478661L;
DeterministicSeed seed = new DeterministicSeed(seedCode, null, passphrase, creationtime);
// The wallet class provides a easy fromSeed() function that loads a new wallet from a given seed.
Wallet wallet = Wallet.fromSeed(params, seed, Script.ScriptType.P2PKH);
you can use bitcore.js for generating mnemonics. I am sharing the link of npm package please have a look.
var Mnemonic = require('bitcore-mnemonic');
var code = new Mnemonic(Mnemonic.Words.SPANISH);
code.toString();
var xpriv = code.toHDPrivateKey();
I am trying to read AWS parameters from the parameter store using java, i have created the parameters using a custom encryption key. I dont see a sample code in the internet where its using a custom KMS key , the below is the code i currently have which is working (here we are usingthe default KMS key).
AWSSimpleSystemsManagement client= AWSSimpleSystemsManagementClientBuilder.defaultClient();
GetParametersRequest request= new GetParametersRequest();
request.withNames("test.username","test.password")
.setWithDecryption(true);
This will give the results with default KMS key
Does anyone know how to handle this if we have a custom KMS key
just in case, if somebody looking for this (with Default encryption Key)
protected Parameter getParameterFromSSMByName(String parameterKey)
{
AWSCredentialsProvider credentials = InstanceProfileCredentialsProvider.getInstance();
AWSSimpleSystemsManagement simpleSystemsManagementClient = (AWSSimpleSystemsManagement)((AWSSimpleSystemsManagementClientBuilder)((AWSSimpleSystemsManagementClientBuilder)AWSSimpleSystemsManagementClientBuilder.standard().withCredentials(credentials)).withRegion("us-east-1")).build();
GetParameterRequest parameterRequest = new GetParameterRequest();
parameterRequest.withName(parameterKey).setWithDecryption(Boolean.valueOf(true));
GetParameterResult parameterResult = simpleSystemsManagementClient.getParameter(parameterRequest);
return parameterResult.getParameter();
}
Here is #Extreme's answer as a class with imports and a bit of cleanup:
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.InstanceProfileCredentialsProvider;
import com.amazonaws.services.simplesystemsmanagement.AWSSimpleSystemsManagement;
import com.amazonaws.services.simplesystemsmanagement.AWSSimpleSystemsManagementClientBuilder;
import com.amazonaws.services.simplesystemsmanagement.model.GetParameterRequest;
import com.amazonaws.services.simplesystemsmanagement.model.GetParameterResult;
public class AWSSsmHelper
{
private AWSCredentialsProvider credentials = InstanceProfileCredentialsProvider.getInstance();
private AWSSimpleSystemsManagement simpleSystemsManagementClient =
AWSSimpleSystemsManagementClientBuilder.standard().withCredentials(credentials)).withRegion("us-east-1")).build();
public String getParameterFromSSMByName(String parameterKey) {
GetParameterRequest parameterRequest = new GetParameterRequest();
parameterRequest.withName(parameterKey).setWithDecryption(Boolean.valueOf(true));
GetParameterResult parameterResult = simpleSystemsManagementClient.getParameter(parameterRequest);
return parameterResult.getParameter().getValue();
}
}
For GetParameters API, there's no difference between use default KMS key or custom KMS key. It always works like your code. Just make sure the permission for the credential includes the custom key.
The difference only at PutParameter API, when using a default KMS key, you don't need to specify it, when using a custom KMS key, you set its KeyId to the custom key. The KeyId can be one of following examples:
Key ARN Example arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012
Alias ARN Example - arn:aws:kms:us-east-1:123456789012:alias/MyAliasName
Globally Unique Key ID Example - 12345678-1234-1234-1234-123456789012
Alias Name Example - alias/MyAliasName
I use shiro in application for the authenticate. I use hashed password with a salt and I store them in my database like this :
private User createUserWithHashedPassword(String inName, String inFirstName, String inLastName, String inPassword){
ByteSource salt = randomNumberGenerator.nextBytes(32);
byte[] byteTabSalt = salt.getBytes();
String strSalt = byteArrayToHexString(byteTabSalt);
String hashedPasswordBase64 = new Sha256Hash(inPassword, salt, 1024).toBase64();
return new User(inName,inFirstName,inLastName,hashedPasswordBase64,strSalt);
}
I store the salt with a String in my database. Now in my realm I want to get back my datas from the database, I use a transactionnal service for this. But my salt is a Strong so I want it to turn back as ByteSource type with the static method :
ByteSource byteSourceSalt = Util.bytes(salt); //where the salt is a String
But when I create my SaltedAuthenticationInfo it doesn't auth.
I think my problem is from my convert method :
private String byteArrayToHexString(byte[] bArray){
StringBuffer buffer = new StringBuffer();
for(byte b : bArray) {
buffer.append(Integer.toHexString(b));
buffer.append(" ");
}
return buffer.toString().toUpperCase();
}
Thanks for your help.
As mentioned in the excellent answer https://stackoverflow.com/a/20206115/603901, Shiro's DefaultPasswordService already generates unique salts for each password.
However, there is no need to implement a custom PasswordService to add a private salt (sometimes called "pepper") to the per-user salts. Private salt can be configured in shiro.ini:
[main]
hashService = org.apache.shiro.crypto.hash.DefaultHashService
hashService.hashIterations = 500000
hashService.hashAlgorithmName = SHA-256
hashService.generatePublicSalt = true
# privateSalt needs to be base64-encoded in shiro.ini but not in the Java code
hashService.privateSalt = myVERYSECRETBase64EncodedSalt
passwordMatcher = org.apache.shiro.authc.credential.PasswordMatcher
passwordService = org.apache.shiro.authc.credential.DefaultPasswordService
passwordService.hashService = $hashService
passwordMatcher.passwordService = $passwordService
Java code for generating a matching password hash:
DefaultHashService hashService = new DefaultHashService();
hashService.setHashIterations(HASH_ITERATIONS); // 500000
hashService.setHashAlgorithmName(Sha256Hash.ALGORITHM_NAME);
hashService.setPrivateSalt(new SimpleByteSource(PRIVATE_SALT)); // Same salt as in shiro.ini, but NOT base64-encoded.
hashService.setGeneratePublicSalt(true);
DefaultPasswordService passwordService = new DefaultPasswordService();
passwordService.setHashService(hashService);
String encryptedPassword = passwordService.encryptPassword("PasswordForThisUser");
The resulting hash looks like this:
$shiro1$SHA-256$500000$An4HRyqMJlZ58utACtyGDQ==$nKbIY9Nd9vC89G4SjdnDfka49mZiesjWgDsO/4Ly4Qs=
The private salt is not stored in the database, which makes it harder to crack the passwords if an adversary gains access to a database dump.
This example was created using shiro-1.2.2
Thanks to https://github.com/Multifarious/shiro-jdbi-realm/blob/master/src/test/resources/shiro.ini for help with the syntax for shiro.ini
Have you looked at PasswordMatcher / PasswordService?
This already has all of the encoding/decoding/compare logic built-in. To use it:
Storing password in database:
PasswordService service = new DefaultPasswordService(); // or use injection or shiro.ini to populate this
private User createUserWithHashedPassword(String inName, String inFirstName, String inLastName, String inPassword){
String hashedPasswordBase64 = service.encryptPassword(inPassword);
return new User(inName,inFirstName,inLastName,hashedPasswordBase64,strSalt);
}
Then you can simply use PasswordMatcher as the matcher in your realm.
realm.setCredentialsMatcher(new PasswordMatcher());
or in shiro.ini:
matcher = org.apache.shiro.authc.credential.PasswordMatcher
realm.credentialsMatcher = $matcher
The DefaultPasswordService implementation automatically adds a random salt to each encryptPassword call. That "public" salt will be stored within the "hashedPasswordBase64" that you receive from "encryptPassword".
Because the "public" salt is individually generated for each hashed password one cannot "simply" generate a rainbow table and brute-force all your hashed passwords at once. For each hashed password the attacker would have to generate an own, unique rainbow table because of the unique "public" salt. So far you do not need to put an extra salt into the database.
To make your stored hashed passwords even more secure you can furthermore add a "private" salt that should be stored anywhere else - as long as not in the database. By using a "private" salt you could protect the hashed passwords against a brute-force rainbow-table attack, because the attacker does not know the "private" salt and cannot gain the "private" salt from the database entries.
This is a very basic example how to create a PasswordService that utilizes a "private" salt provided as a constant string and that works as CredentialsMatcher:
public class MyPrivateSaltingPasswortService extends DefaultPasswordService
{
public MyPrivateSaltingPasswortService()
{
super();
HashService service = getHashService();
if (service instanceof DefaultHashService)
{
((DefaultHashService) service).setPrivateSalt(
new SimpleByteSource("MySuperSecretPrivateSalt"));
}
}
}
you then could use your own implementation in shiro.ini:
[main]
saltedService = com.mycompany.MyPrivateSaltingPasswortService
matcher = org.apache.shiro.authc.credential.PasswordMatcher
matcher.passwordService = $saltedService
realm.credentialsMatcher = $matcher
This example was created using shiro-1.2.2
I change my type for the save of my salt. Now I'm using a byte[] instead of a String.
ByteSource salt = randomNumberGenerator.nextBytes(32);
byte[] byteTabSalt = salt.getBytes();
And I stock the byteTabSalt in my database.