AWS Encryption SDK Encrypt/Decrypt with Data Key - java

I'm attempting to encrypt data using KMS and the AWS Encryption SDK. Looking at the example provided in the AWS documentation, it appears that there is nowhere to explicitly set the data key.
I've found API documentation for the EncryptionMaterialsRequest class that allows you to set the plaintext key using the associated builder class, EncryptionMaterialsRequest.Builder, and this class has a method that returns an instance of EncryptionMaterials. I can't find anywhere to use the EncryptionMaterials instance when executing the encrypt operation.
Here is the code I have so far. Note that the EncryptionMaterials instance isn't used in the request.
public static void encryptData(String dataToEncrypt, String keyID) {
final KmsMasterKeyProvider prov = new KmsMasterKeyProvider(keyID);
DefaultCryptoMaterialsManager manager = new DefaultCryptoMaterialsManager(prov);
byte[] plaintextKey = generateDataKey(keyID);
EncryptionMaterialsRequest request = EncryptionMaterialsRequest
.newBuilder()
.setPlaintext(plaintextKey)
.build();
EncryptionMaterials materials = manager.getMaterialsForEncrypt(request);
AwsCrypto crypto = new AwsCrypto();
String encryptedString = crypto.encryptString(manager, dataToEncrypt).getResult();
}
public byte[] generateDataKey(String keyID) {
GenerateDataKeyRequest dataKeyRequest = new GenerateDataKeyRequest();
dataKeyRequest.setKeyId(keyID);
dataKeyRequest.setKeySpec(DataKeySpec.AES_256);
GenerateDataKeyResult dataKeyResult = kmsClient.generateDataKey(dataKeyRequest);
ByteBuffer encryptedKey = dataKeyResult.getCiphertextBlob();
byte[] arr = new byte[encryptedKey.remaining()];
encryptedKey.get(arr);
return arr;
}
What is the recommended approach encrypting data using the AWS Encryption SDK with a data key generated by KMS?

#Viccari is correct, but it sounds like some context around the intended use of these constructs would help explain why.
Unless you are building a custom cryptographic materials manager you should not be creating EncryptionMaterials; the client and management components take care of that for you.
The client asks the cryptographic materials manager for encryption materials on every encrypt call. Depending on the cryptographic materials manager, what exactly happens next might be different.
In the case of the DefaulCryptoMaterialsManager, it then asks the provided master key provider for all of the master keys to use, then uses those master keys to generate and encrypt the data key (one is used to generate and encrypt, any additional are used to encrypt).
In the case of the CachingCryptoMaterialsManager, it adds a caching layer between the client and another cryptographic materials manager.
If you want to use the AWS Encryption SDK with AWS KMS, the recommended approach is to simply provide an instance of KmsMasterKey or KmsMasterKeyProvider, or a cryptographic materials manager that ultimately uses one of those, in the encrypt call. All of the details are taken care of by the client.
If you're interested in more details about how these concepts fit together, our concepts documentation[1] would be a good place to start.
[1] https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html

My question for you would be: why not using the DefaultCryptoMaterialsManager, which should generate a new data key from the master key for each encryption operation? Why are you going to reuse the data keys? This does not sound like a sound approach from the security perspective.
But if you want to do that, you need to provide an implementation of the CryptoMaterialsManager interface.
Instead of using DefaultCryptoMaterialsManager, create a new class, let's say, MyCryptoMaterialsManager, that implements the interface above.
Something like this would do it:
public static void encryptData(String dataToEncrypt, String keyID) {
// not sure whether you need this or where you're getting the data key from.
final KmsMasterKeyProvider prov = new KmsMasterKeyProvider(keyID);
MyCryptoMaterialsManager manager = new MyCryptoMaterialsManager(prov);
byte[] plaintextKey = generateDataKey(keyID);
EncryptionMaterialsRequest request = EncryptionMaterialsRequest
.newBuilder()
.setPlaintext(plaintextKey)
.build();
// this, you told you know how to do:
EncryptionMaterials materials = manager.getMaterialsForEncrypt(request);
AwsCrypto crypto = new AwsCrypto();
String encryptedString = crypto.encryptString(manager, dataToEncrypt).getResult();
}
public byte[] generateDataKey(String keyID) {
GenerateDataKeyRequest dataKeyRequest = new GenerateDataKeyRequest();
dataKeyRequest.setKeyId(keyID);
dataKeyRequest.setKeySpec(DataKeySpec.AES_256);
GenerateDataKeyResult dataKeyResult = kmsClient.generateDataKey(dataKeyRequest);
ByteBuffer encryptedKey = dataKeyResult.getCiphertextBlob();
byte[] arr = new byte[encryptedKey.remaining()];
encryptedKey.get(arr);
return arr;
}
If cost or number of calls to KMS is a concern, you could also use the CachingCryptoMaterialsManager instead. It provides guarantees like making sure that a data key is not used an indefinite number of times.

Related

Can the key be empty while generating HmacSHA256 using java

I am generating HMAC-SHA256 in Java. If the key is set to "" then The following exception is thrown:
java.lang.IllegalArgumentException: Empty key
But I can generate the HMAC using empty key in JavaScript using the
CryptoJS.HmacSHA256("Sample Text", "") method in CryptoJS. In Java a space is also accepted as key but empty key is not accepted.
Is it possible to use empty key in Java?
Java - as most programming languages - is Turing complete, so you can do any calculation that another language can do, even if you have to program it yourself.
Unfortunately the exception you've shown is part of SecretKeySpec, which means that you cannot generate the key directly. You cannot just use a different provider either because the key creation would be the same.
However, if you're smart then you'll see that SecretKey is just an interface, which means you can implement it:
public static class EmptyKey implements SecretKey {
private static final long serialVersionUID = 1L;
#Override
public String getAlgorithm() {
return "HMAC";
}
#Override
public String getFormat() {
return "RAW";
}
#Override
public byte[] getEncoded() {
// return empty key data
return new byte[0];
}
}
now apparently the HMAC implementation of Java doesn't disallow empty keys itself, so this will work. Of course it might not work in different implementations or versions of Java, although inserting a check in HMAC doesn't seem likely as it could be a valid use case of HMAC.
Alternatively you can of course use another library that implements HMAC, such as Bouncy Castle, and sidestep the JCA altogether.
HMac hmac = new HMac(new SHA256Digest());
hmac.init(new KeyParameter(new byte[0]));
byte[] out = new byte[hmac.getMacSize()];
// you need to insert the message here, I'm using an empty message
hmac.doFinal(out, 0);
Of course, if your code requires a Java Mac object then this is not the solution for you.
The code in both options in this answer produce the same results, so you can be pretty sure that it is valid.

GOST 3411 Algorithm using Bouncy Castle

Am using GOST algorithm to create a hash based on key and input using Bouncy castle libs. Below code generates Hash that doesn't match with the one generated through online tools such as http://beautifytools.com/hmac-generator.php
HMac gMac= new HMac(new GOST3411Digest());
byte[] key = "keyphrase".getBytes();
byte[] input = "macinput".getBytes();
gMac.init(new KeyParameter(key));
gMac.update(input, 0, input.length);
byte[] mac = new byte[gMac.getMacSize()];
gMac.doFinal(mac, 0);
BigInteger in = new BigInteger(1, mac);
System.out.println(in.toString(16));
When this works, Need to use inside Mulesoft to call API which validates the Hash and gives authentication. Basically, The encyption is for generation of authentication token.
Have been referring to stackoverflow for a long time but never had an opportunity to post any questions. This is my first :)
Thanks,
Sudeep
GOST3411 algorithm has several SBox options, so try using different upon initialization. I had some luck with "D-Test" SBox, it matches with most if not all online tools. You can initialize different SBox like this:
HMac mac = new HMac(new GOST3411Digest(GOST28147Engine.getSBox("D-Test")));

CSR generation using java or BouncyCastle without using Private key

Want to create a CSR file in java, when the private/public key pair are getting generated in HSM(Hardware Security Module).
On trying out the examples in Bouncy Castle, the generation of CSR requires both the private key and public key.As the generation of keys is happening in HSM, i have only the public key and the private key sham object.
Can i generate CSR in java without having the private key?
Please find the code sample i was trying.
KeyPair pair = generateKeyPair();
PKCS10CertificationRequestBuilder p10Builder = new JcaPKCS10CertificationRequestBuilder(
new X500Principal("CN=Requested Test Certificate"), pair.getPublic());
JcaContentSignerBuilder csBuilder = new JcaContentSignerBuilder("SHA256withRSA");
ContentSigner signer = csBuilder.build(pair.getPrivate());
PKCS10CertificationRequest csr = p10Builder.build(signer);
I am pretty new to HSM, and any input or reference will be helpful.
You can generate a CSR without having the value of the private key. You do need a reference to the private key, and the key must be capable of signing. References to private keys are just special versions of classes that implement PrivateKey. They don't contain the data, just the reference. Calling getEncoded or retrieving a private exponent of an RSA key will however (usually - it may depend on the key generation parameters and PKCS#11 middleware) fail with an exception.
The way these keys can be used is by just providing them to an init method of a newly generated Signature instance. The Java runtime will then search for the right SignatureSpi implementation in the right provider (the one for your HSM). This is called delayed provider selection as it only searches for an implementation after the init method is called. Of course in your case this will all happen out of sight by the ContentSigner.
The private key data should not leave your HSM at any time, unless wrapped for backup or sharing between HSM's.

Handling passwords used for auth in source code

Assuming that I'm trying to pull from a RESTful api that uses basic authentication / basic certificates, what would be the best way to store that user name and password in my program? Right now it's just sitting there in plaintext.
UsernamePasswordCredentials creds = new UsernamePasswordCredentials("myName#myserver","myPassword1234");
Is there some way of doing this that is more security minded?
Thanks
Important note:
If you're designing the authentication system as a whole, you shouldn't store passwords, even if they're encrypted. You store a hash, and check if passwords provided during login match the same hash. That way, a security breach on your database avoids getting your users' passwords exposed.
With that said, for situations where you are going to store data as-is (in this case passwords), then with an inner-to-outer mindset, here are some steps to protect your process:
First step, you should change your password-handling from String to character array.
The reason for this is that a String is an immutable object, and so it's data will not be cleansed immediately even if the object is set to null; The data is set for garbage-collection instead, and this poses security problems because malicious programs might gain access to that String (password) data before it is cleaned.
This is the main reason why Swing's JPasswordField's getText() method is deprecated, and why getPassword() uses character arrays.
The second step is to encrypt your credentials, only decrypting them temporarily during the authentication process. Or to hash them server-side, store that hash, and "forget" the original password.
This, similarly to the first step, makes sure your vulnerability-time is as small as possible.
It is recommended that your credentials are not hard-coded, and that instead, you store them in a centralized, configurable and easily-maintainable manner, such as a configuration or properties file, or a database.
You should encrypt your credentials before saving the file, and additionally, you can apply a second encryption to the file itself (2-layer encryption to the credentials, and 1-layer to other file contents).
Note that each of the two encryption processes mentioned above can be multiple-layered themselves. Each encryption can be an individual application of Triple Data Encryption Standard (AKA TDES and 3DES), as a conceptual example.
After your local environment is properly protected (but remember, it's never ever "safe"!), the third step is apply basic protection to your transmission process, by using TLS (Transport Layer Security) or SSL (Secure Sockets Layer).
The forth step is to apply other protection methods.
For example, applying obfuscation techniques to your "to-use" compile, to avoid (even if shortly) the exposure of your security measures in case your program is obtained by Ms. Eve, Mr. Mallory, or someone else (the bad-guys) and decompiled.
UPDATE 1:
By #Damien.Bell 's request, here is an example that covers the first and second steps:
//These will be used as the source of the configuration file's stored attributes.
private static final Map<String, String> COMMON_ATTRIBUTES = new HashMap<String, String>();
private static final Map<String, char[]> SECURE_ATTRIBUTES = new HashMap<String, char[]>();
//Ciphering (encryption and decryption) password/key.
private static final char[] PASSWORD = "Unauthorized_Personel_Is_Unauthorized".toCharArray();
//Cipher salt.
private static final byte[] SALT = {
(byte) 0xde, (byte) 0x33, (byte) 0x10, (byte) 0x12,
(byte) 0xde, (byte) 0x33, (byte) 0x10, (byte) 0x12,};
//Desktop dir:
private static final File DESKTOP = new File(System.getProperty("user.home") + "/Desktop");
//File names:
private static final String NO_ENCRYPTION = "no_layers.txt";
private static final String SINGLE_LAYER = "single_layer.txt";
private static final String DOUBLE_LAYER = "double_layer.txt";
/**
* #param args the command line arguments
*/
public static void main(String[] args) throws GeneralSecurityException, FileNotFoundException, IOException {
//Set common attributes.
COMMON_ATTRIBUTES.put("Gender", "Male");
COMMON_ATTRIBUTES.put("Age", "21");
COMMON_ATTRIBUTES.put("Name", "Hypot Hetical");
COMMON_ATTRIBUTES.put("Nickname", "HH");
/*
* Set secure attributes.
* NOTE: Ignore the use of Strings here, it's being used for convenience only.
* In real implementations, JPasswordField.getPassword() would send the arrays directly.
*/
SECURE_ATTRIBUTES.put("Username", "Hypothetical".toCharArray());
SECURE_ATTRIBUTES.put("Password", "LetMePass_Word".toCharArray());
/*
* For demosntration purposes, I make the three encryption layer-levels I mention.
* To leave no doubt the code works, I use real file IO.
*/
//File without encryption.
create_EncryptedFile(NO_ENCRYPTION, COMMON_ATTRIBUTES, SECURE_ATTRIBUTES, 0);
//File with encryption to secure attributes only.
create_EncryptedFile(SINGLE_LAYER, COMMON_ATTRIBUTES, SECURE_ATTRIBUTES, 1);
//File completely encrypted, including re-encryption of secure attributes.
create_EncryptedFile(DOUBLE_LAYER, COMMON_ATTRIBUTES, SECURE_ATTRIBUTES, 2);
/*
* Show contents of all three encryption levels, from file.
*/
System.out.println("NO ENCRYPTION: \n" + readFile_NoDecryption(NO_ENCRYPTION) + "\n\n\n");
System.out.println("SINGLE LAYER ENCRYPTION: \n" + readFile_NoDecryption(SINGLE_LAYER) + "\n\n\n");
System.out.println("DOUBLE LAYER ENCRYPTION: \n" + readFile_NoDecryption(DOUBLE_LAYER) + "\n\n\n");
/*
* Decryption is demonstrated with the Double-Layer encryption file.
*/
//Descrypt first layer. (file content) (REMEMBER: Layers are in reverse order from writing).
String decryptedContent = readFile_ApplyDecryption(DOUBLE_LAYER);
System.out.println("READ: [first layer decrypted]\n" + decryptedContent + "\n\n\n");
//Decrypt second layer (secure data).
for (String line : decryptedContent.split("\n")) {
String[] pair = line.split(": ", 2);
if (pair[0].equalsIgnoreCase("Username") || pair[0].equalsIgnoreCase("Password")) {
System.out.println("Decrypted: " + pair[0] + ": " + decrypt(pair[1]));
}
}
}
private static String encrypt(byte[] property) throws GeneralSecurityException {
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
SecretKey key = keyFactory.generateSecret(new PBEKeySpec(PASSWORD));
Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
pbeCipher.init(Cipher.ENCRYPT_MODE, key, new PBEParameterSpec(SALT, 20));
//Encrypt and save to temporary storage.
String encrypted = Base64.encodeBytes(pbeCipher.doFinal(property));
//Cleanup data-sources - Leave no traces behind.
for (int i = 0; i < property.length; i++) {
property[i] = 0;
}
property = null;
System.gc();
//Return encryption result.
return encrypted;
}
private static String encrypt(char[] property) throws GeneralSecurityException {
//Prepare and encrypt.
byte[] bytes = new byte[property.length];
for (int i = 0; i < property.length; i++) {
bytes[i] = (byte) property[i];
}
String encrypted = encrypt(bytes);
/*
* Cleanup property here. (child data-source 'bytes' is cleaned inside 'encrypt(byte[])').
* It's not being done because the sources are being used multiple times for the different layer samples.
*/
// for (int i = 0; i < property.length; i++) { //cleanup allocated data.
// property[i] = 0;
// }
// property = null; //de-allocate data (set for GC).
// System.gc(); //Attempt triggering garbage-collection.
return encrypted;
}
private static String encrypt(String property) throws GeneralSecurityException {
String encrypted = encrypt(property.getBytes());
/*
* Strings can't really have their allocated data cleaned before CG,
* that's why secure data should be handled with char[] or byte[].
* Still, don't forget to set for GC, even for data of sesser importancy;
* You are making everything safer still, and freeing up memory as bonus.
*/
property = null;
return encrypted;
}
private static String decrypt(String property) throws GeneralSecurityException, IOException {
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
SecretKey key = keyFactory.generateSecret(new PBEKeySpec(PASSWORD));
Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
pbeCipher.init(Cipher.DECRYPT_MODE, key, new PBEParameterSpec(SALT, 20));
return new String(pbeCipher.doFinal(Base64.decode(property)));
}
private static void create_EncryptedFile(
String fileName,
Map<String, String> commonAttributes,
Map<String, char[]> secureAttributes,
int layers)
throws GeneralSecurityException, FileNotFoundException, IOException {
StringBuilder sb = new StringBuilder();
for (String k : commonAttributes.keySet()) {
sb.append(k).append(": ").append(commonAttributes.get(k)).append(System.lineSeparator());
}
//First encryption layer. Encrypts secure attribute values only.
for (String k : secureAttributes.keySet()) {
String encryptedValue;
if (layers >= 1) {
encryptedValue = encrypt(secureAttributes.get(k));
} else {
encryptedValue = new String(secureAttributes.get(k));
}
sb.append(k).append(": ").append(encryptedValue).append(System.lineSeparator());
}
//Prepare file and file-writing process.
File f = new File(DESKTOP, fileName);
if (!f.getParentFile().exists()) {
f.getParentFile().mkdirs();
} else if (f.exists()) {
f.delete();
}
BufferedWriter bw = new BufferedWriter(new FileWriter(f));
//Second encryption layer. Encrypts whole file content including previously encrypted stuff.
if (layers >= 2) {
bw.append(encrypt(sb.toString().trim()));
} else {
bw.append(sb.toString().trim());
}
bw.flush();
bw.close();
}
private static String readFile_NoDecryption(String fileName) throws FileNotFoundException, IOException, GeneralSecurityException {
File f = new File(DESKTOP, fileName);
BufferedReader br = new BufferedReader(new FileReader(f));
StringBuilder sb = new StringBuilder();
while (br.ready()) {
sb.append(br.readLine()).append(System.lineSeparator());
}
return sb.toString();
}
private static String readFile_ApplyDecryption(String fileName) throws FileNotFoundException, IOException, GeneralSecurityException {
File f = new File(DESKTOP, fileName);
BufferedReader br = new BufferedReader(new FileReader(f));
StringBuilder sb = new StringBuilder();
while (br.ready()) {
sb.append(br.readLine()).append(System.lineSeparator());
}
return decrypt(sb.toString());
}
A full example, addressing every protection step, would far exceed what I think is reasonable for this question, since it's about "what are the steps", not "how to apply them".
It would far over-size my answer (at last the sampling), while other questions here on S.O. are already directed on the "How to" of those steps, being far more appropriate, and offering far better explanation and sampling on the implementation of each individual step.
If you are using basic auth, you should couple that with SSL to avoid passing your credentials in base64 encoded plain text. You don't want to make it easy for someone sniffing your packets to get your credentials. Also, don't hard code your credentials in your source code. Make them configurable. read them from a config file. You should encrypt the credentials before storing them in a config file and your app should decrypt the credentials once it reads them from the config file.
Why not store credentials in source code
It is generally a good idea to avoid to store credentials in source code.
The issue is, that access to code and who should have access to the credentials often changes over time. Once a project becomes more mature there are usually some developers who do not need to know and hence should not know certain credentials. In addition code may be reused for slightly different purposes or even become open source. Also, as the code base grows more complex, it becomes very tedious to identify credentials being buried somewhere in the middle of the code.
It seems safe to say that hundreds of millions of users have already been affected by issues caused by hard-coded credentials. Here is an article with some examples.
How to provide credentials to your app
If credentials are not part of the code, this raises the question how you can provide credentials to your application. This depends on the platform on which your application runs. For instance if you host your application on some cloud service, this service will have a mechanism to store credentials in a save way and inject them into the operation system environment of your application. To provide a specific example, here is the documentation how to provide credentials for an app hosted on Heroku.
In you application code you can then access them from the environment. E.g. for Java you could use getenv
String apiPassword = getenv("API_PASSWORD");
Here API_PASSWORD needs to be provided in the environment by the hosting mechanism of your app.
Further Reading
I have written a blog article about the topic that covers this topic in more detail: Keep passwords out of source code - why and how.
It's generally not good advice to encrypt credentials. Something that is encrypted can be decrypted. Common best practice is to store passwords as a salted hash.A hash cannot be decrypted. The salt is added to defeat brute force guessing with Rainbow Tables. As long as every userId has its own random salt, an attacker would have to generate a set of tables for every possible value of the salt, quickly making this attack impossible within the lifespan of the universe. This is the reason why websites generally can't send you your password if you have forgotten it, but they can only 'reset' it. They don't have your password stored, only a hash of it.
Password hashing is not very difficult to implement yourself, but it's such a common problem to solve that countless others have done it for you. I've found jBcrypt easy to use.
As an extra protection against brute force guessing of passwords, it is common best practice to force a userId or remote IP to wait a few seconds after a certain number of login attempts with the wrong password. Without this, a brute force attacker can guess as many passwords per second as your server can handle. There is a huge difference between being able to guess 100 passwords per 10 second period or a million.
I get the impression that you have included the username/password combination in your source code. This means that if you ever want to change the password, you'll have to recompile, stop and restart your service, and it also means that anyone who gets a hold of your source code, also has your passwords. Common best practice is never to do this, but to store the credentials (username, password hash, password salt) in your datastore
secure computer that initializes the request (your computer). if that machine is insecure, nothing will protect you. that's completely separate topic (up-to-date software, properly configured, strong passwords, encrypted swap, hardware sniffers, physical security etc)
secure your storage
the medium you use for storing your credentials should be encrypted. decrypted credentials should be stored only in ram of your secured machine
people that maintain that hardware must be trusted (probably the weakest link)
they also should know as few as possible. that's a protection from rubber-hose cryptanalysis
your credentials should fulfil all the security recommendation (proper length, randomness, single purpose etc)
your connection to remote service must be secured (SSL etc)
your remote service must be trusted (see points 1-4). plus it should be hacking prone (if your data/service is insecure then securing your credentials is pointless). plus it should not store your credentials
plus probably thousand things i forgot about :)
If you cannot trust the environment your program is running in, but need to authenticate via plain passwords or certificates, there is nothing you can do to secure your credentials. The most you can do is obfuscate them with the methods described in the other answers.
As a workaround, I'd run all requests to the RESTful api through a proxy that you can trust and do the cleartext password authentication from there.
why are people talking about hashing. OP wants to store his users credentials to access external resource. Hashing his password will not help.
Now that's out of the way. I would just simple best practices for every layer.
1 . Storing your password in java app. : Store it as Char Array. Create a password store class and store the password as hashmap with key as the resource that you want to access and value as some object that contains of username and password. Restrict the entry point to this api with some authentication Ex: accept the logged in users' credential to validate access level of that user for that resource (simply map user to list of passwords they can access. If you've a lot create a group and map passwordmap key to that group) Anything beyond this to store password depends on how paranoid you're about jvm itself to leak it.
to transmit the password ensure you're sending it on secured portocols (Ex: Https is good, http is bad). If you really must transmit over insecure protocol encrypt it and encode it to say base64. Ensure the recipient decodes and can decrypt your password.

how to generate s3 style access/secret key using java

I am trying to generate access keys and secret keys in the same fashion as S3 using java but am having some trouble.
As a starting point I am looking at this bouncy castle example , I have this code up and running but am not sure of two things 1) how to set it up to use the same key generation as s3 which uses HMAC-SHA1 as outlined here and 2) how to get the friendly public/private key strings out for the the user.
You may have guessed I am new to java encryption and the bouncy castle libraries, however I did find JCEKeyGenerator.HMACSHA1 in the bc docs but am unable to find an example of its use. Any help would be greatly appreciated.
Thanks.
You'll need to make use of javax.crypto.KeyGenerator to create the AWSAccessKeyId and the AWSSecretAccessKey:
javax.crypto.KeyGenerator generator = javax.crypto.KeyGenerator.getInstance("HMACSHA1");
generator.init(120);
byte[] awsAccessKeyId = generator.generateKey().getEncoded();
generator.init(240);
byte[] awsSecretAccessKey = generator.generateKey().getEncoded();
Then, you'll want to base64 encode the bytes (this uses MimeUtility from mail.jar):
final ByteArrayOutputStream encoded = new ByteArrayOutputStream();
final OutputStream encoder = javax.mail.internet.MimeUtility.encode(encoded, "base64");
encoder.write(awsAccessKeyId);
encoder.flush();
encoder.close();
String accessKeyId = new String(encoded.toByteArray(), encoding).replaceAll("[\\r\\n]", "");

Categories