BouncyCastle J2ME RSA using custom keys - blackberry

I would like to use BouncyCastle J2ME/RIM Crypto in my Blackberry Application.
The issue i'm having is that I would like to generate the public key for encryption from a C#.NET program that sends the key to the BlackBerry.
Is it possible to encrypt a message using a raw string? Also, do I need to know other common variable such as modulo etc? Apologies but i'm completely new to cryptography algorithms.
Do I need BouncyCastle for this or can the above be done with RIM Crypto?
Thanks,
Conor

I did it using bouncycastle, but with RIM Crypto is similar.
Follow the example. As you can see the keys are strings ... :
public CypherDecypherExample()
{
String plain ="a plain string";
String cipher = null;
String decipher = null;
byte [] byte_cipher = null;
byte [] byte_plain = null;
// key |-- 128 bit -->|-- 256 bit --->|
String key = "aaaaaaaaaaaaaaaacccccccccccccccc";
String iv = "bbbbbbbbbbbbbbbb";
System.out.println("bouncycastle.plain: " + plain);
try {
byte_cipher = encrypt(plain.getBytes(), key.getBytes(), iv.getBytes());
cipher = new String(byte_cipher);
System.out.println("bouncycastle.cipher: " + cipher);
} catch (Exception e) {
e.printStackTrace();
}
try {
byte_plain = decrypt(byte_cipher, key.getBytes(), iv.getBytes());
decipher = new String(byte_plain);
System.out.println("bouncycastle.decipher: " + decipher);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static byte[] cipherData(PaddedBufferedBlockCipher cipher, byte[] data)
throws Exception
{
String plain = new String(data);
System.out.println("bouncycastle.cipherData: " + plain);
int minSize = cipher.getOutputSize(data.length);
byte[] outBuf = new byte[minSize];
int length1 = cipher.processBytes(data, 0, data.length, outBuf, 0);
int length2 = cipher.doFinal(outBuf, length1);
int actualLength = length1 + length2;
byte[] result = new byte[actualLength];
System.arraycopy(outBuf, 0, result, 0, result.length);
System.out.println("bouncycastle.cipherData returning");
return result;
}
private static byte[] decrypt(byte[] cipher, byte[] key, byte[] iv) throws Exception
{
PaddedBufferedBlockCipher aes = new PaddedBufferedBlockCipher((BlockCipher) new CBCBlockCipher(
new AESEngine()));
CipherParameters ivAndKey = new ParametersWithIV(new KeyParameter(key), iv);
aes.init(false, ivAndKey);
return cipherData(aes, cipher);
}
private static byte[] encrypt(byte[] plain, byte[] key, byte[] iv) throws Exception
{
PaddedBufferedBlockCipher aes = new PaddedBufferedBlockCipher(new CBCBlockCipher(
new AESEngine()));
CipherParameters ivAndKey = new ParametersWithIV(new KeyParameter(key), iv);
aes.init(true, ivAndKey);
return cipherData(aes, plain);
}

An RSA public key consists of two components, not just one like I thought.
There is the Exponent and Modulus. These are both number but I pass them to the Blackberry from .NET client as Base64 strings and decode them into byte arrays when be used by the RIM Crypto function as they take Byte arrays as parameters.
byte[] exponent = Base64InputStream.decode("exponent base64 string");
byte[] modulus = Base64InputStream.decode("modulus base64 string");
NoCopyByteArrayOutputStream cipherUserData = new NoCopyByteArrayOutputStream();
RSACryptoSystem cryptoSystem = new RSACryptoSystem(1024);
// Create Public key using your variables from before
RSAPublicKey publicKey = new RSAPublicKey( cryptoSystem, exponent, modulus);
// Encryption engine objects
RSAEncryptorEngine eEngine = new RSAEncryptorEngine(publicKey);
PKCS1FormatterEngine fEngine = new PKCS1FormatterEngine(eEngine);
BlockEncryptor cryptoStream = new BlockEncryptor(fEngine, cipherUserData);
// Read the user data and encrypt while doing so. Remember, cryptoStream writes its data to
// cipherUserData so this is where the encrypted version of userData will end up.
cryptoStream.write( userData, 0, userData.length );
cryptoStream.close();
cipherUserData.close();
String encryptedUserData = new String(cipherUserData.toByteArray());
That's pretty much all there is too it folks, it's straightforward but it took me a long time to get this from the API docs :)
Important note
RSA is limited for encryption purposes in that you can only encrypt a message that <= key size.
That is 117 bytes for 1024 Bit RSA and 245 bytes for 2048 RSA. To encrypt larger messages the accepted way is to encrypt the message using AES or similar then encrypt the AES key with the RSA public key. You will the send the AES ciphertext and also the RSA ciphertext containing the key to decrypt the AES ciphertext.
What I have written above took days of tinkering and reading. I hope it helps somebody achieve their goal faster than that. :)

Related

Error verifying message using Crypto++ on iOS

Problem
I am trying to verify a given message with its signature and public key. It works fine using the iOS provided Security Framework, but I cannot manage to make it work using the Crypto++ library (must use).
I followed the same steps using the CryptoPP Library and verified everything 10 times, rewrote some parts differently, but it still throws the same exception:
"PK_Signer: key too short for this signature scheme"
context
Data worked with
I receive a JWT (Json Web Token) with a header, payload and signature.
I retrieve the service's base64 encoded X509 certificate (which includes the public key).
Steps followed for verification
Certificate
Base64 decode the certificate
Extract the public key from certificate
Signature (third segment of a JWB)
Pad the signature to a multiple of 4 with some "="
URLBase64 decode it
Message to verify
Message = (JSW Header) + "." + (JWT Payload). This is already done in the code, message is argument named "headerAndPayload.
Verify SHA256 bytes with PKCS1, RSA
SHA256 digest of the Message
Verification using:
Public Key
SHA256 Digest of the message
Signature
iOS Working Code
(Only parts that matter, as verification works fine on iOS)
Certificate
NSData *certificateData = [[NSData alloc] initWithBase64EncodedString:certificateString options:0];
SecKeyRef getPublicKeyFromCertificate(certificateData) found online, works fine.
Verify SHA256 bytes with PKCS1, RSA
BOOL PKCSVerifyBytesSHA256withRSA(NSData* message, NSData* signature, SecKeyRef publicKey)
{
size_t signedHashBytesSize = SecKeyGetBlockSize(publicKey);
const void* signedHashBytes = [signature bytes];
size_t hashBytesSize = CC_SHA256_DIGEST_LENGTH;
void* hashBytes = malloc(hashBytesSize);
if (!CC_SHA256([message bytes], (CC_LONG)[message length], hashBytes)) {
return NULL;
}
OSStatus status = SecKeyRawVerify(publicKey,
kSecPaddingPKCS1SHA256,
hashBytes,
hashBytesSize,
signedHashBytes,
signedHashBytesSize);
return status == errSecSuccess;
}
Code using CryptoPP Library (working with same set of data)
I copy/paste the whole code with numbers corresponding to the description and some additional comments, like size of structures returned.
+(bool)verifyBase64EncodedCertificate:(NSString *)certificateString
base64URLEncodedJWTSignature:(NSString *)urlEncodedSignature
message:(NSString *)headerAndPayload
{
// 1. Certificate
// 1.1 Decode the certificate
std::string base64EncodedCertificate = certificateString.UTF8String;
std::string decodedCertificate;
CryptoPP::StringSource ss(base64EncodedCertificate,
true,
new CryptoPP::Base64Decoder(new CryptoPP::StringSink(decodedCertificate))
);
// 1.2 Extract Public Key from certificate
CryptoPP::ByteQueue certificateByteQueue, publicKeyByteQueue;
certificateByteQueue.Put((byte *)&decodedCertificate[0], decodedCertificate.size());
certificateByteQueue.MessageEnd();
try
{
GetPublicKeyFromCert(certificateByteQueue, publicKeyByteQueue);
// This method comes from CryptoPP docs so I assume it works... certificate gets checked again later on.
}
catch(std::exception &)
{
std::cerr << "Failed to extract the public key from the CA certificate." << std::endl;
return nil;
}
//publicKeyByteQueue.CurrentSize() = 294
// 2. Decode Signature
std::string base64URLEncodedSignature = urlEncodedSignature.UTF8String;
unsigned long paddingForURLEncodedSignature = 4 - (base64URLEncodedSignature.length() % 4);
base64URLEncodedSignature.insert(base64URLEncodedSignature.begin(), paddingForURLEncodedSignature, '=');
std::string decodedSignature;
CryptoPP::StringSource ss1(base64URLEncodedSignature,
true,
new CryptoPP::Base64URLDecoder(new CryptoPP::StringSink(decodedSignature))
);
const byte *decodedSignaturePointer = (byte *)&decodedSignature[0];
size_t decodedSignatureSize = decodedSignature.size();
// Certificate Signature as Byte Block
CryptoPP::SecByteBlock certSignature;
certSignature.Assign(decodedSignaturePointer, decodedSignatureSize);
// decodedSignatureSize = 256
// certSignature.size() = 256
// 3. Message to verify (available already concatenated)
std::string message = headerAndPayload.UTF8String;
const byte *messagePointer = (const byte *)message.c_str();
const size_t messageLength = message.length();
// MessageLength = 693
// 4.1 hash message using SHA256
byte digest [CryptoPP::SHA256::DIGESTSIZE];
CryptoPP::SHA256().CalculateDigest(digest, messagePointer, messageLength);
// 4.2 Create Verifier assigned public key and test
CryptoPP::AutoSeededRandomPool prng;
CryptoPP::RSASS<CryptoPP::PKCS1v15, CryptoPP::SHA256>::Verifier verifier;
verifier.AccessKey().Load(publicKeyByteQueue);
if (!verifier.AccessKey().Validate(prng, 3))
{
throw CryptoPP::Exception(CryptoPP::Exception::OTHER_ERROR, "Failed to validate public key");
}
// verifier.SignatureLength() = 256 = certSignature.size()
if(certSignature.size() != verifier.SignatureLength())
{
std::cerr << "The signature size is does not match the algorithm used for signing." << std::endl;
return 0;
}
// 4. Actual Verification (1st way of doing it)
CryptoPP::SignatureVerificationFilter vf(verifier);
try
{
vf.Put(digest, CryptoPP::SHA256::DIGESTSIZE);
vf.Put(certSignature, certSignature.size());
vf.MessageEnd(); // Throws exception here PK_Signer: key too short for this signature scheme
}
catch(std::exception &e)
{
std::cerr << "Caught an exception while verifying the signature:" << std::endl;
std::cerr << "\t" << e.what() << std::endl;
return 0;
}
if(vf.GetLastResult())
{
std::cout << "The signature verified." << std::endl;
}
else
{
std::cout << "Signature verification failed." << std::endl;
}
return 1;
// 4. Actual Verification (2d way of doing it)
bool verified = verifier.VerifyMessage(digest, CryptoPP::SHA256::DIGESTSIZE,
decodedSignaturePointer, decodedSignatureSize);
// Also throw same exception PK_Signer: key too short for this signature scheme
return verified;
The only difference I can see between the pure iOS code and the CryptoPP code is during the verification process, the iOS method takes an additional argument kSecPaddingPKCS1SHA256
SecKeyRawVerify(publicKey,
kSecPaddingPKCS1SHA256,
...)
But otherwise I feel like I have replicated exactly the same concepts using the CryptoPP library.
Any help is very appreciated, thanks.
vf.Put(digest, CryptoPP::SHA256::DIGESTSIZE);
The signature is not the hash size. The signature is the size of the modulus (or more correctly, [0,n-1]). After protocol framing, the signature may be larger than the modulus size. Also see What is the length of an RSA signature? on the Cryptography Stack Exchange.
As for creating an equivalent iOS example, using the "Raw Sign" or "Raw Encrypt", see Raw RSA on the Crypto++ wiki. Its usually a bad idea for you to do the low level things like a modular exponentiation. You should try to stay in the protocols and cryptosystems, like RSASSA_PKCS1v15_SHA_Signer and RSASSA_PKCS1v15_SHA_Verifier.
Also checkout the RSASS class, which is RSA Signature Scheme. I'm guessing you will probably want a RSASS<PKCS1v15, SHA256>::Signer and RSASS<PKCS1v15, SHA256>::Verifier:
$ grep -IR Signer * | grep typedef
luc.h:typedef LUCSS<PKCS1v15, SHA>::Signer LUCSSA_PKCS1v15_SHA_Signer;
pubkey.h: typedef PK_FinalTemplate<TF_SignerImpl<SchemeOptions> > Signer;
pubkey.h: typedef PK_FinalTemplate<DL_SignerImpl<SchemeOptions> > Signer;
rsa.h:typedef RSASS<PKCS1v15, SHA>::Signer RSASSA_PKCS1v15_SHA_Signer;
rsa.h:typedef RSASS<PKCS1v15, Weak1::MD2>::Signer RSASSA_PKCS1v15_MD2_Signer;
rsa.h:typedef RSASS<PKCS1v15, Weak1::MD5>::Signer RSASSA_PKCS1v15_MD5_Signer;

How to convert p12 file to base64 string?

I'm using java apns to push notification to ios devices on my server, Java apns needs a .p12 certificates and password when pushing notification.
ApnsService service =
APNS.newService()
.withCert("/path/to/certificate.p12", "MyCertPassword")
.withSandboxDestination()
.build();
I want to store this type of .p12 into my database since I have more than 1 .p12 files in my system. Our server also allows the third-party to submit their apps to our server. They are required to submit their .p12 files to our server since they want to push notification via our server. We don't want to keep their .p12 files into a folder on our server but database with a base64 string.
I have somequestions here:
How can we convert a .p12 into a base64 string?
How can we restore the .p12 file from a base64 string when I push notification?
Is there any better solutions to get and store .p2 files on my server side?
Thanks in advance.
private static String encodeFileToBase64Binary(String fileName)
throws IOException {
File file = new File(fileName);
byte[] bytes = loadFile(file);
byte[] encoded = Base64.encodeBase64(bytes);
String encodedString = new String(encoded);
return encodedString;
}
private static byte[] loadFile(File file) throws IOException {
InputStream is = new FileInputStream(file);
long length = file.length();
if (length > Integer.MAX_VALUE) {
// File is too large
}
byte[] bytes = new byte[(int)length];
int offset = 0;
int numRead = 0;
while (offset < bytes.length
&& (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
offset += numRead;
}
if (offset < bytes.length) {
throw new IOException("Could not completely read file "+file.getName());
}
is.close();
return bytes;
}

PBKDF2 iterations

I am using simplemembershipprovider in ASP.NET for authentication.
Microsoft's built in crypto method (below) uses 1000 iterations when hashing passwords. Everyone says this is not enough, so my question is: how could I change this? Surely there is a simple way for me to change one number from 1000 to 100000? I don't want to produce my own security code because people say that for an inexperienced developer security code should be kept away. Do I just accept that 1000 is what it is?
/* =======================
* HASHED PASSWORD FORMATS
* =======================
*
* Version 0:
* PBKDF2 with HMAC-SHA1, 128-bit salt, 256-bit subkey, 1000 iterations.
* (See also: SDL crypto guidelines v5.1, Part III)
* Format: { 0x00, salt, subkey }
*/
public static string HashPassword(string password)
{
if (password == null)
{
throw new ArgumentNullException("password");
}
// Produce a version 0 (see comment above) password hash.
byte[] salt;
byte[] subkey;
using (var deriveBytes = new Rfc2898DeriveBytes(password, SaltSize, PBKDF2IterCount))
{
salt = deriveBytes.Salt;
subkey = deriveBytes.GetBytes(PBKDF2SubkeyLength);
}
byte[] outputBytes = new byte[1 + SaltSize + PBKDF2SubkeyLength];
Buffer.BlockCopy(salt, 0, outputBytes, 1, SaltSize);
Buffer.BlockCopy(subkey, 0, outputBytes, 1 + SaltSize, PBKDF2SubkeyLength);
return Convert.ToBase64String(outputBytes);
}

How to reduce memory when loading image from website?

I am using this Utility
public class Util_ImageLoader {
public static Bitmap _bmap;
Util_ImageLoader(String url) {
HttpConnection connection = null;
InputStream inputStream = null;
EncodedImage bitmap;
byte[] dataArray = null;
try {
connection = (HttpConnection) Connector.open(url + Util_GetInternet.getConnParam(), Connector.READ,
true);
inputStream = connection.openInputStream();
byte[] responseData = new byte[10000];
int length = 0;
StringBuffer rawResponse = new StringBuffer();
while (-1 != (length = inputStream.read(responseData))) {
rawResponse.append(new String(responseData, 0, length));
}
int responseCode = connection.getResponseCode();
if (responseCode != HttpConnection.HTTP_OK) {
throw new IOException("HTTP response code: " + responseCode);
}
final String result = rawResponse.toString();
dataArray = result.getBytes();
} catch (final Exception ex) {
}
finally {
try {
inputStream.close();
inputStream = null;
connection.close();
connection = null;
} catch (Exception e) {
}
}
bitmap = EncodedImage
.createEncodedImage(dataArray, 0, dataArray.length);
int multH;
int multW;
int currHeight = bitmap.getHeight();
int currWidth = bitmap.getWidth();
multH = Fixed32.div(Fixed32.toFP(currHeight), Fixed32.toFP(currHeight));// height
multW = Fixed32.div(Fixed32.toFP(currWidth), Fixed32.toFP(currWidth));// width
bitmap = bitmap.scaleImage32(multW, multH);
_bmap = bitmap.getBitmap();
}
public Bitmap getbitmap() {
return _bmap;
}
}
When I call it in a listfield which contains 10 childs, then the log keeps saying failed to allocate timer 0: no slots left.
This means the memory is being used up and no more memory to allocate again and as a result my main screen cannot start.
At the same time you have the following objects in memory:
// A buffer of about 10KB
byte[] responseData = new byte[10000];
// A string buffer which will grow up to the total response size
rawResponse.append(new String(responseData, 0, length));
// Another string the same length that string buffer
final String result = rawResponse.toString();
// Now another buffer the same size of the response.
dataArray = result.getBytes();
It total, if you downloaded n ascii chars, you have simultaneously 10KB, plus 2*n bytes in the first unicode string buffer, plus 2*n bytes in the result string, plus n bytes in dataArray. If I'm not wrong, that sums up to 5n + 10k. There's room for optimization.
Some improvements would be:
Check response code first, and then read the stream if response code is HTTP 200. No need to read if server returned an error.
Get rid of strings. No need to convert to string if after that you are converting again to bytes.
If images are large, don't store them in RAM while downloading. Instead, open a FileOutputStream and write to a temporary file as you read from input stream. Then, if temporary images are still large enough to be displayed, downscale them.

How to achieve minimum size when compressing small amount of data lossless?

I don’t understand the answer to ”Why does gzip/deflate compressing a small file result in many trailing zeroes?”
(Why does gzip/deflate compressing a small file result in many trailing zeroes?)
How would you go about compressing small amount of data ½-2 Kbyte to minimum size in a .NET-environment?
(Runtime is not an issue for me. Can I trade speed for size? Should I use 3rd party products?
Developer license fees are OK, but runtime license not.)
Any suggestions about how I can improve the code below for:
(a) Higher compression ratio?
(b) More proper use of streams?
Here is the C#-code that needs to be improved:
private static byte[] SerializeAndCompress(MyClass myObject)
{
using (var inStream = new System.IO.MemoryStream())
{
Serializer.Serialize< MyClass >(inStream, myObject); // PROTO-buffer serialization. (Code not included here.)
byte[] gZipBytearray = GZipCompress(inStream);
return gZipBytearray;
}
}
private static Byte[] GZipCompress(MemoryStream inStream)
{
inStream.Position = 0;
byte[] byteArray;
{
using (MemoryStream outStream = new MemoryStream())
{
bool LeaveOutStreamOpen = true;
using (GZipStream compressStream = new GZipStream(outStream,
CompressionMode.Compress, LeaveOutStreamOpen))
{
// Copy the input stream into the compression stream.
// inStream.CopyTo(Compress); TODO: "Uncomment" this line and remove the next one after upgrade to .NET 4 or later.
CopyFromStreamToStream(inStream, compressStream);
}
byteArray = CreateByteArrayFromStream(outStream); // outStream is complete first after compressStream have been closed.
}
}
return byteArray;
}
private static void CopyFromStreamToStream(Stream sourceStream, Stream destinationStream)
{
byte[] buffer = new byte[4096];
int numRead;
while ((numRead = sourceStream.Read(buffer, 0, buffer.Length)) != 0)
{
destinationStream.Write(buffer, 0, numRead);
}
}
private static byte[] CreateByteArrayFromStream(MemoryStream outStream)
{
byte[] byteArray = new byte[outStream.Length];
outStream.Position = 0;
outStream.Read(byteArray, 0, (int)outStream.Length);
return byteArray;
}

Resources