How to convert p12 file to base64 string? - ios

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;
}

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;

Xamarin - WCF Upload Large Files Report progress vis UIProgressView

I have create a WCF Service that allows uploading large files via BasicHttpBinding using streaming and it is working great! I would like to extended this to show a progress bar (UIProgressView) so that when a large file is being uploaded in 65k chunks, the user can see that it is actively working.
The client code calling the WCF Service is:
BasicHttpBinding binding = CreateBasicHttp ();
BTSMobileWcfClient _client = new BTSMobileWcfClient (binding, endPoint);
_client.UploadFileCompleted += ClientUploadFileCompleted;
byte[] b = File.ReadAllBytes (zipFileName);
using (new OperationContextScope(_client.InnerChannel)) {
OperationContext.Current.OutgoingMessageHeaders.Add(System.ServiceModel.Channels.MessageHeader.CreateHeader("SalvageId","",iBTSSalvageId.ToString()));
OperationContext.Current.OutgoingMessageHeaders.Add(System.ServiceModel.Channels.MessageHeader.CreateHeader("FileName","",Path.GetFileName(zipFileName)));
OperationContext.Current.OutgoingMessageHeaders.Add(System.ServiceModel.Channels.MessageHeader.CreateHeader("Length","",b.LongLength));
_client.UploadFileAsync(b);
}
On the server side, I read the file stream in 65k chuncks and do report back to the calling routine "bytes read", etc. A snippet of code for that is:
using (FileStream targetStream = new FileStream(filePath, FileMode.CreateNew,FileAccess.Write)) {
//read from the input stream in 65000 byte chunks
const int chunkSize = 65536;
byte[] buffer = new byte[chunkSize];
do {
// read bytes from input stream
int bytesRead = request.FileData.Read(buffer, 0, chunkSize);
if (bytesRead == 0) break;
// write bytes to output stream
targetStream.Write(buffer, 0, bytesRead);
} while (true);
targetStream.Close();
}
But I don't know how to hook into the callback on the Xamarin side to receive the "bytes read" versus "total bytes to send" so I can update the UIProgressView.
Has anyone tried this or is this even possible?
Thanks In Advance,
Bo

BouncyCastle J2ME RSA using custom keys

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. :)

How to send image stored in RMS to server in j2me?

I want to send the image stored in the RMS to server. For that I have stored the captured image in the RMS. I can access it successfully and can show it over device, but when I used to send it to server, that time over the server only name of image appears but the image is not generating.
here is the line code that I am trying to use
byte[] byteArrRec = LoadImagesFromRMS.objImageRecordStore.getRecord(recID);
ByteArrayInputStream bin = new ByteArrayInputStream(byteArrRec);
DataInputStream din = new DataInputStream(bin);
int width = din.readInt();
int height = din.readInt();
int length = din.readInt();
int[] rawImg = new int[width * height];
for (int itemp = 0; itemp < length; itemp++) {
rawImg[itemp] = din.readInt();
}
Image tempImage = Image.createRGBImage(rawImg, width, height, false);
byteArr = get_Byte_Array(tempImage);
byteArr = get_Byte_Array(tempImage);
Then I have passed the byteArray using post method over the server.
But the Image is not been generated, Did any one have any idea about this?
First need to read all bytes from response and store in one variable (bytearray) of byte array. Then after that write this code
Create a ByteArrayInputStream from your byte array and then use ImageIO class to read image from that stream.
InputStream in = new ByteArrayInputStream(bytearray);
BufferedImage image = ImageIO.read(in);
Thanks
you need to create HttpConnection with the remote server, after creating connection , create a DataOutputStream variable associated with the HttpConnection variable.
Now write byte array into that DataOutputStream variable and send it as "POST" method. If byte array's size is very big the try to send it in chunks..

Can we compress a large file as a chunk data for GZIP in blackberry?

I saw the sample APIas below
public static byte[] compress( byte[] data )
{
try
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream gzipStream = new GZIPOutputStream( baos, 6, GZIPOutputStream.MAX_LOG2_WINDOW_LENGTH );
gzipStream.write( data );
gzipStream.close();
}
catch(IOException ioe)
{
return null;
}
return baos.toByteArray();
}
But when I tried to compress with a large file with Curve 8900 OS 4.6, I got a "OutOfMemoryError" so I would like to know that how to compress as a chunk small data?
I already tried with this code as below but it doesn't work, compressed file cannot decompress...
file = (FileConnection)Connector.open(_fileOutputPath, Connector.READ_WRITE);
if (!file.exists()) {
file.create();
}
os = file.openOutputStream();
is = FileUtil.getInputStream(_fileInputPath, 0);
int tmpSize = 1024;
byte[] tmp = new byte[tmpSize];
int len = -1;
gzipStream = new GZIPOutputStream( os, 6, GZIPOutputStream.MAX_LOG2_WINDOW_LENGTH );
while((len = is.read(tmp, 0, tmpSize)) != -1) {
gzipStream.write(tmp, 0, len);
}
GZIPOutputStream does not produce a file suitable for use with the gzip command line tool. This is because it doesn't produce the necessary file headers. How did you test decompressing it? You should write a similar Java program that makes use of GZIPInputStream to test, as 'gunzip' is not going to recognize the input.
The problem of the first code sample is that the ByteArrayOutputStream is getting too big for the limited memory of a mobile device.
An option could be to first write to a file (for instance) on SD card.
The second code sample seems fine, but see Michael's answer.

Resources