RSA - How can the client (in server context) encrypt/decrypt incoming data? - java

I have trouble understanding exactly how RSA works. Many examples and definitions attempt to explain but use a vague context.
So here is what I want to do:
I have a server that uses RSA and has a private and public key. From what I understand, upon connection the server sends the public key to the server in an unencrypted manner.. some kind of handshake if you will.
Further traffic would then occur in an encrypted fashion. To establish this fashion how would I be able to both encrypt what the client sends, and decrypt what the client receives (from client-sided perspective).
On server side encrypted data gets decrypted by the private key but I can't decrypt data in the client without that private key... that I can't have in the client because it's secret.
This confuses me, am I missing something obvious or is there need of a second private key?
Thanks in advance!

As you have already pointed out is RSA an asymmetric encryption scheme, that means:
c = E(pub_key, m) // ciphertext = encryption(public key, message)
m = D(pri_key, c) // message = decryption(private key, ciphertext)
In contrast a symmetric encryption scheme (such as fore example AES) works the following:
c = E(key, m)
m = E(key, c)
In other words the same key is used for encryption and decryption.
And that is where the asymmetric cryptosystem comes into play. It allows to parties to securely exchange a secret key for symmetric encryption.
So basically how a primitive (but very vulnerable!) key exchange could look:
server sends to client his public key pub_key_S
client sends to server his public key encrypted with the server's public key c = E(pub_key_S, pub_key_C)
server decrypts c with his private key pub_key_C = D(pri_key_S, c)
server generates a new random symmetric secret key key_CS
server encrypts the newly generated key with the client's public key c = E(pub_key_C, key_CS)
server sends c to the client
client decrypts ciphertext with his private key pri_key_C key_CS = D(pri_key_C, c)
Now Client and Server have a shared secret key key_CS which they can use to securely communicate for the ongoing session.
Such a protocol is in practice quite a bit more complicated, including certificates, digital signatures, hashcodes and so on. The probably most widely used protocol is SSL or TLS. (for in example https).
I recommend you to check out that link if you are interested in the details of such a protocol.

First read this article. Then you should know that usually asymmetric algorithms using for exchanging passwords and electronic signs. So the best way in client-server encryption is to generate common encryption key (with RSA or Diffie–Hellman key exchange), and then use any of symmetric algo (AES for example) to encode data between server and client.

Related

Would it be possible to sign a jwt token with a RSA public key? [duplicate]

I'm trying to understand the logic of using JSON web tokens with private/public keys (RS512) when signing a payload of data sent from a client (in this case, a React Native App) to my server.
I thought the whole point of private/public keys was to keep the private key private (on my server) and hand the public key to the person who's successfully logged into the app.
I thought, with each API request to my server, the authenticated user of the app would use the public key to create the JWT (on the client side) and the server would use the private key to verify the signature/payload from the API request.
It seems I have it backwards because everywhere I read, you're supposed to sign a JWT with the private key -- but that goes against my understanding of who's in possession of the keys.
Depending on how the keys are created, some private keys can have a passcode which is supposed to be secret! So if the private key and the secret is out in the open (in client-side code) how secure can that be?
And where does the encryption come in? If the user of the app is sending sensitive data in the API, am I supposed to encrypt the payload and sign it with the JWT on the client side and then let the server verify the JWT signature and decrypt the data?
This tutorial was helpful https://medium.com/#siddharthac6/json-web-token-jwt-the-right-way-of-implementing-with-node-js-65b8915d550e but it seems backwards.
Any explanation would definitely help because all of the on-line tutorials aren't making sense.
Thank you.
With JWT, the possession and the use of the key materials are exactly the same as any other contexts where cypher operations occur.
For signing:
The private key is owned by the issuer and is used to compute the signature.
The public key can be shared with all parties that need to verify the signature.
For encryption:
The private key is owned by the recipient and is used to decrypt the data.
The public key can be shared to any party that want to send sensitive data to the recipient.
The encryption is rarely used with JWT. Most of the time the HTTPS layer is sufficient and the token itself only contain a few information that are not sensitive (datatime, IDs...).
The issuer of the token (the authentication server) has a private key to generate signed tokens (JWS). These tokens are sent to the clients (an API server, a web/native application...).
The clients can verify the token with the public key. The key is usually fetched using a public URI.
If you have sensitive data that shall not be disclosed to a third party (phone numbers, personnal address...), then the encrypted tokens (JWE) is highly recommended.
In this case, each client (i.e. recipient of a token) shall have a private key and the issuer of the token must encrypt the token using the public key of each recipient. This means that the issuer of the token can select the appropriate key for a given client.
Hope this figure adds some clarity.
Solution for JWE in React Native and Node Backend
The hardest part was finding a method that works in both RN and Node because I can't just use any Node library in RN.
I'm transmitting all of the API calls over HTTPS.
Create a JWE to encrypt the token and payload simultaneously.
React Native App Code
import {JWK, JWE} from 'react-native-jose';
/**
* Create JWE encrypted web token
*
* #param payload
* #returns {Promise<string>}
*/
async function createJWEToken(payload = {}) {
// This is the Public Key created at login. It is stored in the App.
// I'm hard-coding the key here just for convenience but normally it
// would be kept in a Keychain, a flat file on the mobile device, or
// in React state to refer to before making the API call.
const publicKey = `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApl9FLYsLnP10T98mT70e
qdAeHA8qDU5rmY8YFFlcOcy2q1dijpgfop8WyHu1ULufJJXm0PV20/J9BD2HqTAK
DZ+/qTv4glDJjyIlo/PIhehQJqSrdIim4fjuwkax9FOCuFQ9nesv32hZ6rbFjETe
QSxUPjNzsYGOuULWSR3cI8FuV9InlSZQ7q6dEunLPRf/rZujxiAxGzY8zrMehjM5
LNdl7qDEOsc109Yy3HBbOwUdJyyTg/GRPwklLogw9kkldz5+wMvwOT38IlkO2rCr
qJpqqt1KmxdOQNbeGwNzZiGiuYIdiQWjilq5a5K9e75z+Uivx+G3LfTxSAnebPlE
LwIDAQAB
-----END PUBLIC KEY-----`;
try {
const makeKey = pem => JWK.asKey(pem, 'pem');
const key = await makeKey(publicKey);
// This returns the encrypted JWE string
return await JWE.createEncrypt({
zip: true,
format: 'compact',
}, key).update(JSON.stringify(payload)).final();
} catch (err) {
throw new Error(err.message);
}
}
Node Backend
const keygen = require('generate-rsa-keypair');
const {JWK, JWE} = require('node-jose');
/**
* Create private/public keys for JWE encrypt/decrypt
*
* #returns {Promise<object>}
*
*/
async function createKeys() {
// When user logs in, create a standard RSA key-pair.
// The public key is returned to the user when he logs in.
// The private key stays on the server to decrypt the message with each API call.
// Keys are destroyed when the user logs out.
const keys = keygen();
const publicKey = keys.public;
const privateKey = keys.private;
return {
publicKey,
privateKey
};
}
/**
* Decrypt JWE Web Token
*
* #param input
* #returns {Promise<object>}
*/
async function decryptJWEToken(input) {
// This is the Private Key kept on the server. This was
// the key created along with the Public Key after login.
// The public key was sent to the App and the Private Key
// stays on the server.
// I'm hard-coding the key here just for convenience but
// normally it would be held in a database to
// refer during the API call.
const privateKey = `-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEApl9FLYsLnP10T98mT70eqdAeHA8qDU5rmY8YFFlcOcy2q1di
jpgfop8WyHu1ULufJJXm0PV20/J9BD2HqTAKDZ+/qTv4glDJjyIlo/PIhehQJqSr
dIim4fjuwkax9FOCuFQ9nesv32hZ6rbFjETeQSxUPjNzsYGOuULWSR3cI8FuV9In
lSZQ7q6dEunLPRf/rZujxiAxGzY8zrMehjM5LNdl7qDEOsc109Yy3HBbOwUdJyyT
g/GRPwklLogw9kkldz5+wMvwOT38IlkO2rCrqJpqqt1KmxdOQNbeGwNzZiGiuYId
iQWjilq5a5K9e75z+Uivx+G3LfTxSAnebPlELwIDAQABAoIBAQCmJ2FkMYhAmhOO
LRMK8ZntB876QN7DeT0WmAT5VaE4jE0mY1gnhp+Zfn53bKzQ2v/9vsNMjsjEtVjL
YlPY0QRJRPBZqG3wX5RcoUKsMaxip3dckHo3IL5h0YVJeucAVmKnimIbE6W03Xdn
ZG94PdMljYr4r9PsQ7JxLOHrFaoj/c7Dc7rd6M5cNtmcozqZsz6zVtqO1PGaNa4p
5mAj9UHtumIb49e3tHxr//JUwZv2Gqik0RKkjkrnUmFpHX4N+f81RLDnKsY4+wyI
bM5Gwq/2t8suZbwfHNFufytaRnRFjk+P6crPIpcfe05Xc+Y+Wq4yL62VY3wSS13C
EeUZ2FXpAoGBANPtw8De96TXsxdHcbmameWv4uepHUrYKq+7H+pJEGIfJf/1wsJ0
Gc6w2AE69WJVvCtTzP9XZmfiIze2sMR/ynhbUl9wOzakFpEh0+AmJUG+lUHOy4k2
Mdmu6GmeIM9azz6EXyfXuSZ39LHowS0Es1xaWRuu5kta73B5efz/hz2tAoGBAMj4
QR87z14tF6dPG+/OVM/hh9H5laKMaKCbesoXjvcRVkvi7sW8MbfxVlaRCpLbsSOs
cvAkc4oPY+iQt8fJWSJ1nwGJ0g7iuObLJh9w6P5C3udCGLcvqNbmQ9r+edy1IDBr
t7pdrFKiPFvaEEqYl06gVSsPCg041N6bRTJ1nEzLAoGAajSOVDqo6lA6bOEd6gDD
PSr+0E+c4WQhSD3Dibqh3jpz5aj4uFBMmptfNIaicGw8x43QfuoC5O6b7ZC9V0wf
YF+LkU6CLijfMk48iuky5Jao3/jNYW7qXofb6woWsTN2BoN52FKwc8nLs9jL7k6b
wB166Hem636f3cLS0moQEWUCgYABWjJN/IALuS/0j0K33WKSt4jLb+uC2YEGu6Ua
4Qe0P+idwBwtNnP7MeOL15QDovjRLaLkXMpuPmZEtVyXOpKf+bylLQE92ma2Ht3V
zlOzCk4nrjkuWmK/d3MzcQzu4EUkLkVhOqojMDZJw/DiH569B7UrAgHmTuCX0uGn
UkVH+wKBgQCJ+z527LXiV1l9C0wQ6q8lrq7iVE1dqeCY1sOFLmg/NlYooO1t5oYM
bNDYOkFMzHTOeTUwbuEbCO5CEAj4psfcorTQijMVy3gSDJUuf+gKMzVubzzmfQkV
syUSjC+swH6T0SiEFYlU1FTqTGKsOM68huorD/HEX64Bt9mMBFiVyA==
-----END RSA PRIVATE KEY-----`;
try {
const makeKey = pem => JWK.asKey(pem, 'pem');
const key = await makeKey(privateKey);
// This returns the decrypted data
return await JWE.createDecrypt(key).decrypt(input);
} catch (err) {
throw new Error(err.message);
}
}
jwt.io does a great job of explaining that there is more than one way to sign the JWT. Users may sign and verify with a single secret, or use a public/private key pair for verifying/signing respectively.
JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA.
Although JWTs can be encrypted to also provide secrecy between
parties, we will focus on signed tokens. Signed tokens can verify the
integrity of the claims contained within it, while encrypted tokens
hide those claims from other parties. When tokens are signed using
public/private key pairs, the signature also certifies that only the
party holding the private key is the one that signed it.

Bouncycastle: encrypt with a public key

I need some help with this lib. Fetching the following examples code BouncyCastle and I do not understand how this works.
My code: http://pastebin.com/RieDfUd9
Dictionary: chain[0], is sender cert.
conv, is the receiver cert.
My problem is this, I need to encrypt an email using smime with the public key personnel which I am sending the email. At the moment in my test environment I have access to both certificates. But in a production environment I will have only access to my certificate (who is sending) chain [0], and the public key of those who receive. I need encryptar email so that I can open with the public key of who is reading (and which was used to encrypt the message).
I already tried several ways, but I always have problems when decrypting.
You cannot do that. You will have to store the cert instead of just the public keys.
When a mail client receive a email, it has to know which private key to use to decrypt it - or it will just fail to decrypt.
How does the mail client knows which private key to use? Because recipient information is also in the encrypted mail.
You can't just encrypt your data encryption key with any random public key and hope the receiver knows which key can be used to decrypt it.
That's why the BouncyCastle API takes a certificate instead of a key.
You can more read about the details of SMIME encryption here:
https://security.stackexchange.com/questions/45222/smime-email-decryption-key-with-openssl
This link has more about how the decryption process is done for multiple recipients:
SMIME decryption for multiple recipients

How to encrypt/decrypt sent/received messages in Android? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
We are building a chat client (something like Whatsapp, etc.) for sending and receiving private messages. For the sake of privacy we decided to encrypt and decrypt the messages upon arrival and sending.
I figured we could use RSA private and public keys for encryption. I understand that we usually need two pairs of keys, one of which residing on the server and one on the phone. This brings up some questions which I'm asking here.
How to generate a key pair in android?
How should they be stored?
Do I need different key pairs for every user on the server as well as on the clients?
Please feel free to add any useful information for I am a complete newbie in security.
The most commonly used encryption/decryption technique is AES. You can find more information Visit http://en.wikipedia.org/wiki/Advanced_Encryption_Standard?
You simply need to define a KEY(anything like for example: 25346483936) which will be common both at mobile as well as server end along with an IV_Vector which is required for Cryptography it will be more clear from the code below.
Note: The length of the key must be equal to IV_Vector array size, it is 16 in the below example. Now using the encrypt method you can encrypt any information before sending it to server over a non-secure network. Similarly you can decrypt information received from server using DecryptData class.
public class Constants {
// encryption/decryption
public static String AES_KEY = "0366D8637F9C6B21";
public static byte[] IV_VECTOR = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
}
/**
* This class is used to decrypt an encrypted string value.
*
* #author kthakur
*
*/
public class EncryptDecrytData {
/**
* This method is used to encrypt a string value.
*
* #param text
* - string value to be encrypted.
*
* #return result(encrypted string) as String
*
* #throws Exception
*
*/
#TargetApi(8)
public static String encrytData(String text) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
byte[] static_key = Constants.AES_KEY.getBytes();
SecretKeySpec keySpec = new SecretKeySpec(static_key, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(Constants.IV_VECTOR);
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
byte[] results = cipher.doFinal(text.getBytes());
String result = Base64.encodeToString(results, Base64.NO_WRAP|Base64.DEFAULT);
return result;
}
/**
* This method is used to decrypt a string value.
*
* #param text
* - string value to be decrypted.
* #return result(decrypted string) as String
*
* #throws Exception
*/
#SuppressLint("NewApi")
public static String decryptData(String text)throws Exception{
byte[] encryted_bytes = Base64.decode(text, Base64.DEFAULT);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
byte[] static_key = Constants.AES_KEY.getBytes();
SecretKeySpec keySpec = new SecretKeySpec(static_key, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(Constants.IV_VECTOR);
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
byte[] decrypted = cipher.doFinal(encryted_bytes);
String result = new String(decrypted);
return result;
}
}
You will need a central server which provides certificates for each user to authenticate users (otherwise you will always be vulnerable to a man in the middle attack). So for two users (Joe and Sally), there will be three certificates: 1) the certificate authenticating your central server, 2) the certificate authenticating Joe and 3) the certificate authenticating Sally.
So when Joe wants to initiate communication with Sally the following should happen:
Joe requests Sally's public key from the central server.
Joe authenticates the server via the server's public key (by checking the digital certificate).
Joe uses the server's public key to encrypt a shared secret key and then sends the encrypted shared secret key to the server.
Only the server can decrypt Joe's shared secret key and thus uses this shared secret key to encrypt (via Symmetric Cryptography) Sally's public key and sends Sally's public key, encrypted via Joe's proposed shared secret key, to Joe.
Joe now has Sally's public key; authenticated because it came from an authenticated server.
Joe sends a request to Sally to initiate communication identifying themselves as "Joe" along with a digital certificate.
Sally authenticates "Joe" via the central server.
Sally retrieves Joe's public key in the same way that Joe obtained Sally's public key from the central server.
Sally sends a shared secret key to Joe.
Sally uses Joe's public key to encrypt a multi-part message which includes 1) the shared secret key and 2) a digital certificate encrypted with Sally's private key.
Joe receives Sally's encrypted message (which only Joe can decrypt since it was encrypted with Joe's public key).
Joe decrypts the message and receives Sally's proposed shared secret key.
Joe receives Sally's digital certificate, encrypted with Joe's public key, and attempts to decrypt with Sally's public key obtained previously from the central server.
If Joe successfully decrypts the digital certificate, then Joe can be assured that Sally is the one who proposed the shared secret key.
Joe sends an acknowledgement of the shared secret to Sally via symmetric cryptography, using the shared secret key.
Sally receives Joe's acknowledgement via Sally's proposed shared secret key.
Sally and Joe can now communicate back and forth using symmetric cryptography via Sally's originally proposed shared secret key.
So why is all of this necessary? First, you need a "trusted" broker (that's the central server). Otherwise you can never be sure who you are communicating with. You may ask: why does Sally need to sign her shared secret key when only Joe can decrypt it anyway (if Sally uses Joe's public key to encrypt)? The reason is that anyone can encrypt a shared secret key via Joe's public key! Therefore if Joe receives an unsigned shared secret key, he may start communicating with a man in the middle who simply generated a shared secret key using Joe's public key. Just as Sally needs some confirmation that Joe is the actual entity trying to communicate with her, Joe needs some assurance that the shared secret key he receives is actually from Sally (hence why she needs to sign with her private key).
RSA is not safe!!! Given enough traffic, it is possible to decrypt messages encoded by RSA. Thus, you should have a protocol in place for periodically updating public/private keys used for authentication. This is simple for users: your central server will hold the public keys for each user. Periodically your server should request that each user generate a new private/public key pair and send the public key to the server to be updated (this communication can be done via the previous private/public key used by each user).
It's a little more "difficult" for the central server itself. If your central server wishes to change its private/public key (authenticating the server), then it needs to communicate with every user to make each user aware of the change. When a user changes his/her private/public key, it's a one-to-one communication (just between the user and the server) but when the server wants to change its private/public key, it must communicate with all users!
Caveat:
I don't claim that what I proposed above is the "canonical" pattern. What I claim, is that if you follow the above, you will will ensure both authenticity and integrity. I.e. you can be guaranteed to be communicating with the entity the central server considers to be "Joe" and "Sally" and you can guarantee that only Joe and Sally can communicate because no one, including the central server, knows the shared secret key used by Joe and Sally to communicate (except for Joe and Sally of course).
There are many encryption/decryption algorithms such as Data Encryption Standards (DES), Playfair, etc., etc.
You may use those. And if you like, make your own algorithm. I once made a messenger app and I made my own algorithm for encryption/decryption.
You may also choose to have a symmetric or asymmetric key algorithm... Keep working, messengers have a nice scope.. :)

How do I RSA encrypt a string with a plaintext key using Java BouncyCastle API on Android

I am trying to encrypt a string using the BouncyCastle API in Android to send off to a server.
I have the public key in plaintext (in memory, not in the filesystem, of course! no need to yell at me, cryptographers ;) ) and I need to use this plaintext public key to encrypt a string to an RSA encrypted string.
This is my class:
public class RSAEncryptor {
//Get certificate from base64 string
public static X509Certificate getCertificateFromBase64String(String string)
throws CertificateException, javax.security.cert.CertificateException
{
if(string.equals("") || string == null) {
return null;
}
byte[] certBytes = Base64.decode(string.getBytes(), Base64.DEFAULT);
X509Certificate cert = X509Certificate.getInstance(certBytes);
return cert;
}
//Get public key from base64 encoded string
public static PublicKey getPublicKeyFromEncodedCertData(String encodedCertData)
throws CertificateException, javax.security.cert.CertificateException
{
if(encodedCertData == null || encodedCertData.equals("")) return null;
X509Certificate cert = getCertificateFromBase64String(encodedCertData);
if(cert == null) return null;
return cert.getPublicKey();
}
public static String rsaEncrypt(String plainText, String keyFromResources)
throws NoSuchAlgorithmException, InvalidKeySpecException,
IOException, NoSuchPaddingException, InvalidKeyException,
IllegalBlockSizeException, BadPaddingException //
{
if(plainText == null || plainText.equals("")) return null;
if(keyFromResources == null || keyFromResources.equals("")) return null;
byte[] encryptedBytes;
Cipher cipher = Cipher.getInstance("RSA");
PublicKey publicKey = null;
try {
publicKey = getPublicKeyFromEncodedCertData(keyFromResources);
}
catch(Exception ex) {
Logger.LogError("getPublicKeyFromEncodedCertData()", ex);
}
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
encryptedBytes = cipher.doFinal(plainText.getBytes());
String encrypted = new String(encryptedBytes);
return encrypted;
}
}
I'm currently not getting the properly encrypted string back out, just a garbled mess like this:
��RB��%����I��Q��F*�bd[#�y�_H]T{KƾuTN�Q�
��U�f��]�S
�q|.t�t�9�Rˇ�����)��{�},ޱ�ª�ǥ#���#k=�WO���f�7t"yP�z�
(The <?>'s are null chars)
I should be getting back an alphanumeric string similar to this:
2+tSXez8JrAIX+VJ2Dy4IsA56XhWpTwF8X2yGGaI6novucXknwykDyqJZICpmYcqx75qBRgxwrW2kY9LmQR2xU17PLqTukAu2Bna8WXYTmJJQ7CWsN3SdABlETRfsYA+g3A2rO2Qp6aR9OCBcFVJpnZJjb9kaOUj5Pcj0tNPFdM= (changed obviously from the actual response :D)
I'd appreciate any help!
Thanks!
Has anyone done this before? I'd love any suggestions you have as to how to fix this.
Problems in the code:
String encrypted = new String(encryptedBytes);
Bad idea! Cipher#doFinal returns a byte[] for a good reason. It looks like random data - turning this into a String will make a mess for sure, because the platform default encoding (UTF-8 in most cases) will interpret the random bytes wrong almost with certainty. So if you want to have a String from encrypted data, then you should Base64- or Hex-encode the byte array.
From what you said you were expecting I would say you want Base64-encoded data, so you should Base64-encode your Cipher's output.
Then, encrypting a string (is this real, human-readable text?) is also less than optimal. Highly vulnerable, the reduced entropy plus the characteristics of the ECB mode (this is used by the RSA cipher) lower the security of your solution drastically.
A plain RSA cipher should never be used to encrypt data that is larger than one block (i.e. larger than the key size of your RSA key) and also only if the data is cryptographically secure random. In 99% of all cases this is only given for symmetric keys used for symmetric Ciphers such as AES etc.
Use RSA for nothing else than symmetric key wrapping and digital signatures, in all remaining cases where you want to actually encrypt sensitive data, you use a symmetric cipher, AES is a good choice - 128 or 256 bits doesn't really matter.
The workflow would look like this:
Generate a symmetric key for AES (16/32 bytes if you use AES-128/256). Now you would RSA-encrypt this symmetric key and nothing else using the server's public key and send the key to the server, then encrypt your private data using AES and the symmetric key, the server would decrypt the symmetric key using its private RSA key and decrypt the packets you send to it.
Use TLS:
Note my use of would. The above is only part of the story. What you just invented there is a Key Transport Protocol. And unless you are designing those for a living chances are high that you won't get this secure on your first try (as in Man-In-The-Middle-Attacks, Reflection Attacks, Replay Attacks, ...).
That's why in my opinion the only widely available secure option to set up a secure channel between client device and server is to use TLS (the former SSL). The protocol was designed specifically for the purpose of exchanging private data with one-way (server only) or two-way authentication (client and server) (authentication is the part where you would use RSA for in your case - configuring the "server certificate").
It has been hardened for years and revised a couple of times to withstand all known attacks on such protocols. And I know, there are messages every other day about how "SSL" has been broken by this or that person, but still, if you set it up carefully it's as secure as it gets for mere mortals without extensive experience in protocol design.
And the nice thing is you only have to configure it on the server (which is quite easy compared to inventing a protocol from scratch) to be able to use fully encrypted, secure communication between both client and server. If you set up a certificate/key pair on the server that was bought from a "public CA" then using TSL is completely transparent to your clients - they merely change their access URL from 'http' to 'https' - the server's certificate will be automatically trusted by being able to identify it in a certificate path that leads to one of the root certificates kept in Java's default trust store cacerts.

Signing algorithm that works with Android, Java, iPhone, Windows Mobile

Does anyone know of a signing algorithm that will work with all these platforms.
The Server will generate an RSA public and private key through a Java Program. The client application (a mobile phone) will then need to decode a message from the server that is signed using the private key (the public key is stored on the device).
The values below work with Android and Java, however, I am not sure about how they will work with other platforms.
//For the server signed message
public static final int RSA_KEY_SIZE = 2048;
public static final String SIGNATURE_ALGORITHM = "SHA256withRSA";
public static final String RSA = "RSA";
public static final String PROVIDER = "BC"; //Bouncy Castle
//For hashing sensitive data over the network
public static final String SECURE_RANDOM_ALGORITHM = "SHA1PRNG";
You incorrectly understand asymmetric cryptography. To encrypt message, server should use public key of the client, and with his private key client will be able to decrypt message.
What is done with RSA private key is called 'signing'.
In case you need to use encryption with only one hard-coded key, you can use symmetric cryptography (for instance, AES).
One of the points of standardised cryptographic algorithms is that they are interoperable, no matter what code was used to implement them. Thus for example RSA-encrypted message can be created by a server written in Java and decrypted by a .Net client (think about how webservers communicate with browsers using HTTPS - there are no restrictions on which languages can you use to write a server/webbrowser).
For Windows Mobile, there's a Bouncy Castle crypto API implementation available (Compact Framework). For iPhone Objective-C code, some reference can be found in this StackOverflow question.

Categories

Resources