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();
Related
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 set the URI of the Reference node under SignedInfo, under Signature. Why does it not pick the value of the ID from Response object when I sign it?
Here is my code:
QName respQName = new QName(SAMLConstants.SAML20P_NS,Response.DEFAULT_ELEMENT_LOCAL_NAME, "samlp");
Response resp = new ResponseBuilder().buildObject(respQName);
resp.setID(uuid);
//resp.set .......
Signature signature = (Signature) Configuration.getBuilderFactory().getBuilder(Signature.DEFAULT_ELEMENT_NAME) .buildObject(Signature.DEFAULT_ELEMENT_NAME);
signature.setSigningCredential(signingCredential);
signature.setKeyInfo(new SAMLResponseGenerator().getKeyInfo(signingCredential, null, uuid));
assertion.setSignature(signature);
resp.getAssertions().add(assertion);
Signer.signObject(signature);
marshallerFactory = Configuration.getMarshallerFactory();
Element responseTxt = marshallerFactory.getMarshaller(resp).marshall(resp);
System.out.println(XMLHelper.nodeToString(responseTxt));
What am I missing?
In case anybody is facing the same issue: the reference uri seems to come in only when the actual response object is marshalled & then signed. Only signing it without marshalling is not enough. In my case, Iam encrypting the assertion after signing it.
Element responseTxt = new ResponseMarshaller().marshall(resp);
Signer.signObject(signature);
EncryptedAssertion encryptedAssertion = getEncryptedAssertion(resp.getAssertions().get(0), credential);
resp.getAssertions().clear();
resp.getEncryptedAssertions().add(encryptedAssertion);
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'm a beginner with Apache Shiro. I've been following the docs and lots of other tutorials, blogs etc. but I just can't get the authentication to work. When I attempt to login with a valid username and password, I always get an InvalidCredentialsException thrown. I'm using DynamoDB as a custom realm for storing user credentials, but I really don't think that matters. It's obviously the way that I'm storing and/or doing the credential matching that's not correct. Here's my setup:
Shiro.ini:
[main]
myRealm = com.enki.closing.users.DynamoDBRealm
credentialsMatcher = org.apache.shiro.authc.credential.Sha256CredentialsMatcher
credentialsMatcher.storedCredentialsHexEncoded = false
credentialsMatcher.hashIterations = 1024
myRealm.credentialsMatcher = $credentialsMatcher
Create user account:
String password = ...
ByteSource passwordSalt = new SecureRandomNumberGenerator().nextBytes();
String hashedPasswordBase64 = new Sha256Hash(password, passwordSalt, 1024).toBase64();
// store the hashedPassword and salt in DynamoDB...
// I've tried storing the salt with and without base64 encoding.
The password and salt are stored fine in DynamoDB, the values look alright. Here's the custom realm for authentication:
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken userPass = (UsernamePasswordToken) token;
String username = userPass.getUsername();
...
// pull the matching password and salt out of DynamoDB, no problems...
ByteSource passwordSalt = ByteSource.Util.bytes( storedPasswordSalt );
return new SimpleAuthenticationInfo(username, passwordHash, passwordSalt, getName());
}
This is all pretty much what the docs are telling me to do, but there's something not right. When I try the login, it get InvalidCredentialsException.
I figured out how to get it working. I had to change this (in my custom realm impl):
ByteSource passwordSalt = ByteSource.Util.bytes( storedPasswordSalt );
to this:
ByteSource passwordSalt = ByteSource.Util.bytes(
Base64.decode( storedPasswordSalt) );
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.