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
Related
Trying to delete multiple row of DynamoDB.
Querying only on one table of DynamoDB.On basis the of Partition key, its returning 2 values as output, which is save in list.
Now after deleting this value using BatchDelete only first element get deleted. Sometimes on random basis second value also get deleted but that was not happened every time.
DynamoDBQueryExpression<Abc> queryExpression = new DynamoDBQueryExpression<Abc>()
.withHashKeyValues(abc);
List<Abc> xyz = dynamoDBMapper.query(Abc.class,queryExpression);
//xyz has size 2
dynamoDBMapper.batchDelete(xyz);
Should I use sleep or is there any other way.
If you look at Java V1 here:
https://github.com/awsdocs/aws-doc-sdk-examples
You will see it's marked as deprecated.
I strongly recommend that you upgrade to the AWS SDK for Java v2 API.
When working with Java V2 and DynamoDB, the Enhanced Client offers a straightforward way to map client-side classes to DynamoDB tables. This is documented in the Java V2 Developer Guide here:
Mapping items in DynamoDB tables
To use the Enhanced Client to delete multiple items, you can use this Java code:
package com.example.dynamodb;
// snippet-start:[dynamodb.java2.mapping.batchdelete.import]
import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider;
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient;
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable;
import software.amazon.awssdk.enhanced.dynamodb.Key;
import software.amazon.awssdk.enhanced.dynamodb.TableSchema;
import software.amazon.awssdk.enhanced.dynamodb.model.BatchWriteItemEnhancedRequest;
import software.amazon.awssdk.enhanced.dynamodb.model.DeleteItemEnhancedRequest;
import software.amazon.awssdk.enhanced.dynamodb.model.WriteBatch;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
// snippet-end:[dynamodb.java2.mapping.batchdelete.import]
/*
* Before running this code example, create an Amazon DynamoDB table named Customer with these columns:
* - id - the id of the record that is the key
* - custName - the customer name
* - email - the email value
* - registrationDate - an instant value when the item was added to the table
*
* Also, ensure that you have set up your development environment, including your credentials.
*
* For information, see this documentation topic:
*
* https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/get-started.html
*/
public class EnhancedBatchDeleteItems {
public static void main(String[] args) {
ProfileCredentialsProvider credentialsProvider = ProfileCredentialsProvider.create();
Region region = Region.US_EAST_1;
DynamoDbClient ddb = DynamoDbClient.builder()
.region(region)
.credentialsProvider(credentialsProvider)
.build();
DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder()
.dynamoDbClient(ddb)
.build();
deleteBatchRecords(enhancedClient);
ddb.close();
}
// snippet-start:[dynamodb.java2.mapping.batchdelete.main]
public static void deleteBatchRecords(DynamoDbEnhancedClient enhancedClient) {
try {
DynamoDbTable<Customer> mappedTable = enhancedClient.table("Customer", TableSchema.fromBean(Customer.class));
Key key1 = Key.builder()
.partitionValue("id110")
.build();
Key key2 = Key.builder()
.partitionValue("id120")
.build();
BatchWriteItemEnhancedRequest request = BatchWriteItemEnhancedRequest.builder()
.writeBatches(WriteBatch.builder(Customer.class)
.mappedTableResource(mappedTable)
.addDeleteItem(DeleteItemEnhancedRequest.builder()
.key(key1)
.build())
.build(),
WriteBatch.builder(Customer.class)
.mappedTableResource(mappedTable)
.addDeleteItem(DeleteItemEnhancedRequest.builder()
.key(key2)
.build())
.build())
.build();
// Delete these two items from the table.
enhancedClient.batchWriteItem(request);
System.out.println("Records deleted");
} catch (DynamoDbException e) {
System.err.println(e.getMessage());
System.exit(1);
}
}
// snippet-end:[dynamodb.java2.mapping.batchdelete.main]
}
You can find this example and other Java v2 DynamoDB examples in AWS Code Example Github.
I do not see any issue with your code, I have tested similar and works for me with no issue. My first suggestion would be to ensure you wrap your code in a try/catch block:
try {
DynamoDBMapper mapper = new DynamoDBMapper(client);
Reply key = new Reply();
key.setPk("1");
DynamoDBQueryExpression<Reply> queryExpression = new DynamoDBQueryExpression<Reply>()
.withHashKeyValues(key)
.withReturnConsumedCapacity(ReturnConsumedCapacity.TOTAL)
.withScanIndexForward(false);
List<Reply> latestReplies = mapper.query(Reply.class, queryExpression);
// Log keys here to be sure you are deleting the correct item
for (Reply c: latestReplies) {
System.out.println(c.getPk());
}
mapper.batchDelete(latestReplies);
} catch (Throwable t) {
System.err.println("Error running: " + t);
t.printStackTrace();
}
I would suggest that you implement some logging, just to be sure that the items you read are the ones you expected to be deleted.
It may also be worth enabling CloudTrail Dataplane Logs which will allow you to see all the dataplane events being executed on the table.
You may also enable HTTP wire logging to provide you another level of logging, however, this is not advised for production workloads as the logging is quite verbose.
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!
how can I use key alias in Encrypted sharedprefernces?
below is my Encrypted shared preference
KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(
DEFAULT_MASTER_KEY_ALIAS,
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setKeySize(DEFAULT_AES_GCM_MASTER_KEY_SIZE)
.build();
MasterKey masterKey = new MasterKey.Builder(this)
.setKeyGenParameterSpec(spec)
.build();
SharedPreferences sharedPreferences = EncryptedSharedPreferences.create(this,
this.getResources().getString(R.string.app_preferences),
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
);
I got below exception when implemented this,
W/AndroidKeysetManager: keyset not found, will generate a new one
java.io.FileNotFoundException: can't read keyset; the pref value __androidx_security_crypto_encrypted_prefs_key_keyset__ does not exist
at com.google.crypto.tink.integration.android.SharedPrefKeysetReader.readPref(SharedPrefKeysetReader.java:71)
at com.google.crypto.tink.integration.android.SharedPrefKeysetReader.readEncrypted(SharedPrefKeysetReader.java:89)
at com.google.crypto.tink.KeysetHandle.read(KeysetHandle.java:105)
at com.google.crypto.tink.integration.android.AndroidKeysetManager$Builder.read(AndroidKeysetManager.java:311)
at com.google.crypto.tink.integration.android.AndroidKeysetManager$Builder.readOrGenerateNewKeyset(AndroidKeysetManager.java:287)
at com.google.crypto.tink.integration.android.AndroidKeysetManager$Builder.build(AndroidKeysetManager.java:238)
at androidx.security.crypto.EncryptedSharedPreferences.create(EncryptedSharedPreferences.java:155)
at androidx.security.crypto.EncryptedSharedPreferences.create(EncryptedSharedPreferences.java:120)
I need to replace DEFAULT_MASTER_KEY_ALIAS with key alias mentioned in that box?
If yes, then how can I do that without hardcoding?
I have replaced DEFAULT_MASTER_KEY_ALIAS with key alias mentioned in Project Structure under modules. Got below exception.
java.lang.IllegalArgumentException: KeyGenParamSpec's key alias does not match provided alias (_androidx_security_master_key_ vs mykeyalias
Your problem comes from this line:
MasterKey masterKey = new MasterKey.Builder(this)
According to the implementation of MasterKey.Builder(), if you don't provide the second parameter that is the key alias
public Builder(#NonNull Context context, #NonNull String keyAlias) {
mContext = context.getApplicationContext();
mKeyAlias = keyAlias;
}
Then the default key alias is being used
public Builder(#NonNull Context context) {
this(context, MasterKey.DEFAULT_MASTER_KEY_ALIAS);
}
So once you try to build with a KeyGenParameterSpec with a different alias, it is complaining. Make use of the constructor with the key alias as second parameter, then it should work.
Sorry being late answering, I've just faced the same problem. I've preferred to share this to help others while looking for an answer.
You don't necessarily need to use keyalias in this case. But I couldn't use KeyGenParameterSpec so I used KeyScheme and it worked for me. Try using it:
MasterKey masterKey = new MasterKey.Builder(this)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.build();
Instead of:
MasterKey masterKey = new MasterKey.Builder(this)
.setKeyGenParameterSpec(spec)
.build();
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();
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.