craterdog.security.RsaAesMessageCryptex Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of java-secure-messaging-providers Show documentation
Show all versions of java-secure-messaging-providers Show documentation
This project defines algorithm specific Java providers that implement the secure messaging API.
/************************************************************************
* Copyright (c) Crater Dog Technologies(TM). All Rights Reserved. *
************************************************************************
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. *
* *
* This code is free software; you can redistribute it and/or modify it *
* under the terms of The MIT License (MIT), as published by the Open *
* Source Initiative. (See http://opensource.org/licenses/MIT) *
************************************************************************/
package craterdog.security;
import craterdog.utils.Base64Utils;
import craterdog.utils.RandomUtils;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.Signature;
import java.security.spec.AlgorithmParameterSpec;
import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
/**
* This class implements the interfaces needed to do message level symmetric key encryption and
* decryption when the sender and receiver have already exchanged their asymmetric public keys.
* The public/private key pair are RSA based, and the symmetric key type is AES.
*
* @author Derk Norton
*/
public final class RsaAesMessageCryptex extends MessageCryptex {
static private final String ENCODING_TYPE = "AES-128-CBC-PKCS7";
static private final String ASYMMETRIC_KEY_TYPE = "RSA";
static private final String HASH_ALGORITHM = "SHA256";
static private final String ASYMMETRIC_SIGNATURE_ALGORITHM = "SHA1with" + ASYMMETRIC_KEY_TYPE;
static private final String ASYMMETRIC_ENCRYPTION_ALGORITHM = ASYMMETRIC_KEY_TYPE + "/NONE/OAEPWithSHA256AndMGF1Padding";
static private final String SYMMETRIC_KEY_TYPE = "AES";
static private final int SYMMETRIC_KEY_SIZE = 128;
static private final String SYMMETRIC_ENCRYPTION_ALGORITHM = SYMMETRIC_KEY_TYPE + "/CBC/PKCS7Padding";
static private final String PROVIDER_NAME = BouncyCastleProvider.PROVIDER_NAME;
/**
* This default constructor creates the cryptex and initializes the security provider.
*/
public RsaAesMessageCryptex() {
logger.entry();
Security.addProvider(new BouncyCastleProvider());
logger.exit();
}
@Override
public String getEncodingType() {
return ENCODING_TYPE;
}
@Override
public String getAsymmetricSignatureAlgorithm() {
return ASYMMETRIC_SIGNATURE_ALGORITHM;
}
@Override
public String getAsymmetricEncryptionAlgorithm() {
// this should be changed to the preferred algorithm after August, 2014
return ASYMMETRIC_ENCRYPTION_ALGORITHM;
}
@Override
public String getSymmetricEncryptionAlgorithm() {
return SYMMETRIC_ENCRYPTION_ALGORITHM;
}
@Override
public int getSymmetricKeySize() {
return SYMMETRIC_KEY_SIZE;
}
@Override
public String getHashAlgorithm() {
return HASH_ALGORITHM;
}
@Override
public byte[] signBytes(PrivateKey privateKey, byte[] bytes) {
try {
logger.entry();
Signature signer = Signature.getInstance(ASYMMETRIC_SIGNATURE_ALGORITHM, PROVIDER_NAME);
signer.initSign(privateKey);
signer.update(bytes);
byte[] signature = signer.sign();
logger.exit();
return signature;
} catch (GeneralSecurityException e) {
logger.catching(e);
RuntimeException exception =
new RuntimeException("An exception occured while trying to sign bytes.", e);
throw exception;
}
}
@Override
public boolean bytesAreValid(PublicKey certificate, byte[] bytes, byte[] signature) {
try {
logger.entry();
Signature signer = Signature.getInstance(ASYMMETRIC_SIGNATURE_ALGORITHM, PROVIDER_NAME);
signer.initVerify(certificate);
signer.update(bytes);
boolean isValid = signer.verify(signature);
logger.exit();
return isValid;
} catch (GeneralSecurityException e) {
logger.catching(e);
RuntimeException exception =
new RuntimeException("An exception occured while trying to validate signed bytes.", e);
throw exception;
}
}
@Override
public SecretKey generateSharedKey() {
try {
logger.entry();
KeyGenerator keyGenerator = KeyGenerator.getInstance(SYMMETRIC_KEY_TYPE, PROVIDER_NAME);
keyGenerator.init(SYMMETRIC_KEY_SIZE, RandomUtils.generator);
SecretKey sharedKey = keyGenerator.generateKey();
logger.exit();
return sharedKey;
} catch (GeneralSecurityException e) {
logger.catching(e);
RuntimeException exception =
new RuntimeException("An exception occured while trying to generate a shared key.", e);
throw exception;
}
}
@Override
public byte[] encryptSharedKey(PublicKey publicKey, SecretKey sharedKey) {
try {
logger.entry();
// this should change to the real algorithm (with OAEP padding) after August, 2014
Cipher cipher = Cipher.getInstance(ASYMMETRIC_ENCRYPTION_ALGORITHM, PROVIDER_NAME);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedKey = cipher.doFinal(sharedKey.getEncoded());
logger.exit();
return encryptedKey;
} catch (GeneralSecurityException e) {
logger.catching(e);
RuntimeException exception =
new RuntimeException("An exception occured while trying to encrypt a shared key.", e);
throw exception;
}
}
@Override
public SecretKey decryptSharedKey(PrivateKey privateKey, byte[] encryptedKey) {
try {
logger.entry();
byte[] decryptedKey;
Cipher cipher = Cipher.getInstance(ASYMMETRIC_ENCRYPTION_ALGORITHM, PROVIDER_NAME);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
decryptedKey = cipher.doFinal(encryptedKey);
SecretKey sharedKey = new SecretKeySpec(decryptedKey, SYMMETRIC_ENCRYPTION_ALGORITHM);
logger.exit();
return sharedKey;
} catch (GeneralSecurityException e) {
logger.catching(e);
RuntimeException exception =
new RuntimeException("An exception occured while trying to decrypt a shared key.", e);
throw exception;
}
}
@Override
public CipherOutputStream encryptionOutputStream(SecretKey sharedKey, OutputStream output)
throws IOException {
try {
logger.entry();
logger.debug("Creating and initializing the encryption engine...");
Cipher cipher = Cipher.getInstance(SYMMETRIC_ENCRYPTION_ALGORITHM, PROVIDER_NAME);
byte[] fixedIV = new byte[16]; // all zeros
AlgorithmParameterSpec ivSpec = new IvParameterSpec(fixedIV);
cipher.init(Cipher.ENCRYPT_MODE, sharedKey, ivSpec);
logger.debug("Creating a special output stream to do the work...");
CipherOutputStream cipherOutputStream = new CipherOutputStream(output, cipher);
logger.exit();
return cipherOutputStream;
} catch (GeneralSecurityException e) {
logger.catching(e);
RuntimeException exception =
new RuntimeException("An exception occured while trying to encrypt a stream.", e);
throw exception;
}
}
@Override
public CipherInputStream decryptionInputStream(SecretKey sharedKey, InputStream input)
throws IOException {
try {
logger.entry();
logger.debug("Creating and initializing the decryption engine...");
Cipher cipher = Cipher.getInstance(SYMMETRIC_ENCRYPTION_ALGORITHM, PROVIDER_NAME);
byte[] fixedIV = new byte[16]; // all zeros
AlgorithmParameterSpec ivSpec = new IvParameterSpec(fixedIV);
cipher.init(Cipher.DECRYPT_MODE, sharedKey, ivSpec);
logger.debug("Creating a special input stream to do the work...");
CipherInputStream cipherInputStream = new CipherInputStream(input, cipher);
logger.exit();
return cipherInputStream;
} catch (GeneralSecurityException e) {
logger.catching(e);
RuntimeException exception =
new RuntimeException("An exception occured while trying to decrypt a stream.", e);
throw exception;
}
}
@Override
public String hashString(String string) {
try {
logger.entry();
byte[] bytes = (string).getBytes();
MessageDigest hasher = MessageDigest.getInstance(HASH_ALGORITHM);
byte[] hash = hasher.digest(bytes);
String hashString = Base64Utils.encode(hash);
logger.exit();
return hashString;
} catch (NoSuchAlgorithmException e) {
RuntimeException exception = new RuntimeException("An unexpected exception occurred while attempting to hash a string.", e);
logger.throwing(exception);
throw exception;
}
}
}