IOS: Decrypting a message with public key received from webservice - iphone

I'm new to this topic so sorry if this is a stupid question :\
I'm trying to decrypt a message with a given public key. Both the message and public key is given from the webservice.
See the following code for how i currently do the decrypting:
for (NSValue *refVal in keyRefs) {
SecKeyRef p_key = NULL;
[refVal getValue:&p_key];
if (p_key == NULL) continue;
size_t dataLength = encryptedData.length;
size_t outPutLength = MAX(dataLength, SecKeyGetBlockSize(p_key));
void *outPutBuf = malloc(outPutLength);
if (outPutBuf) {
// Error handling
OSStatus status = SecKeyDecrypt(p_key,
kSecPaddingNone,
encryptedData.bytes,
encryptedData.length,
outPutBuf,
&outPutLength
);
NSLog(#"decryption result code: %ld (size: %lu)", status, outPutLength);
NSLog(#"FINAL decrypted text: %s", outPutBuf);
if (status == errSecSuccess) {
break;
}
} else {
//Error handling
}
}
I get no errors, but the decrypted string is displayed like this (the correct output should be a JSON array):
decryption result code: 0 size:511)
FINAL decrypted text: ˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇ
Is it because I use the "SecKeyDecrypt" with a "public key" instead of a "private key"? In that case, what should i instead use for decrypting?
Thanks for any help regarding this!
EDIT: I'm using code from: http://blog.flirble.org/2011/01/05/rsa-public-key-openssl-ios/ to use the public key i get from the server (this is where "keyRefs" from the code snippet comes from)

Of course, the public key is something someone else uses to encrypt data so that only someone with the private key can decrypt it.
The very definition of a public key is that you can give it to anyone. You wouldn't want anyone to be able to decrypt anyone else's encrypted message would you?
It is impossible to tell from your code fragment where your private key is stored, or what the contents (or even class) of keyRefs is.
EDIT: In response to above OP's comment. And clarification.
*"The public key itself is the public part of a RSA-key-pair stored on the server. The encrypted message was created on the server by first JSON-encoding the object, then encrypted with the private-key with OPENSSL_PKCS1_PADDING, then base64-encoded, and then JSON-encoded again as a part of the final message. The message and public key is stored on the client. What i want is to decrypt the message on the client by using the public key. As i said, im not very good at this subject so i might have tried to do this the wrong way"*
Thats not how public key cryptography works. The server and client exchange public keys. Then each of them use the other's public key to encrypt data sent to the opposite party. The receiving party always uses their own private key to decrypt the message.
If you want the server to generate an encrypted response, have the client pass their public key in the request, use that public key to encrypt the response, and then decrypt the response on the client with the client's private key.

Related

Using spring-security-oauth2 Authorization Server with kid and JWKS?

Following the documentation here and there, I managed to setup an Authorization Server that gives out JWT access tokens signed with asymmetric key, which are verified locally by a Resource Server using a local copy of the public key. So far so good.
My final goal is for Resource Servers to use the JWKS endpoint on the Authorization Server, and use the 'kid' header in the JWT to lookup the right key in the JWKS and verify locally, supporting key rotation.
I've found how to make the Authorization Server expose a JWKS endpoint, and also how to specify the key-set-uri for the resource server.
However, it seems that there is no way to
publish kid (key id) values in the JWKS
include the kid header in the JWT
Is there a way to do this?
I found a way to set the kid in jwks endpoint:
#FrameworkEndpoint
public class JwkSetEndpoint {
private final KeyPair keyPair;
public JwkSetEndpoint(KeyPair keyPair) {
this.keyPair = keyPair;
}
#GetMapping("/.well-known/jwks.json")
#ResponseBody
public Map<String, Object> getKey() {
RSAPublicKey publicKey = (RSAPublicKey) this.keyPair.getPublic();
RSAKey key = new RSAKey.Builder(publicKey)
.keyID("YOUR_KID_HERE")
.keyUse(KeyUse.SIGNATURE).build();
return new JWKSet(key).toJSONObject();
}
}
What I did not find was a way to set it in the header of JWT.
While having the same problem I stumbled upon this post. So i hope it will be useful to someone. I do not think this is the best solution, so maybe some one comes up with a better answer i hope like setting some external bean for example.
Background:
The Jwk store is comparing the KID in the token header with the one in memory if not available it will request the well-known endpoint
So putting the KID in the JwkSetEndpoint will result in a json file with the kid inside.
next to this you need to get the KID on the header of the jwt token.
my solution in my class which extends JwtAccessTokenConverter
#Override
protected String encode(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
String content = null;
try {
content = objectMapper.formatMap(getAccessTokenConverter().convertAccessToken(accessToken, authentication));
} catch (Exception e) {
throw new IllegalStateException("Cannot convert access token to JSON", e);
}
Map<String, String> headers = getJwtHeader();
String token = JwtHelper.encode(content, signer, headers).getEncoded();
return token;
}
next to the KID header the Tokenstore expects a use header set to signing.
i also had to override the signer object because i got stuck with a hmac signer instead of the desired RsaSigner.

Public key encoding changes

I've generated a public key using elliptic curves, but whenever I get the encoding of the key, it changes. I would like to use the encoding for a public address of a blockchain I am implementing. See below
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PublicKey;
import java.security.spec.ECGenParameterSpec;
class Scratch {
public static void main(String[] args) throws Exception {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256k1");
keyGen.initialize(ecSpec);
KeyPair kp = keyGen.generateKeyPair();
PublicKey k = kp.getPublic();
byte[] one = k.getEncoded();
byte[] two = k.getEncoded();
System.out.println(one);
System.out.println(two);
}
}
With output
[B#4eec7777
[B#3b07d329
Does anyone know why this is happening? My guess is that it is the expected behavior and I am just misunderstanding something fundamental here.
You are printing the memory address of the byte[], not the key itself. You can't "print" a byte array because it is binary data, you need to encode it somehow first. Hex and base64 are both good encodings for displaying binary data. For memory, other blockchain implementations like to use base58.
Here is an example using base64:
String b64Str = Base64.getEncoder().encodeToString(one);
System.out.println(b64Str);

How to sign with Bouncy Castle using RSA with SHA1 and ISO9796-2 scheme 2?

I need to sign the SHA1 hash of a text with RSA and ISO9796-2 scheme 2 padding
Initially I was doing it only with SHA1 with RSA like this:
public static byte[] signer(byte[] data, PrivateKey key) throws Exception {
Signature signer = Signature.getInstance("SHA1WithRSA", "BC");
signer.initSign(key);
signer.update(data);
return signer.sign();
}
How should I modify the function? It would be easy to just replace "SHA1WithRSA" with another scheme that does what I need but I don't know if it's possible.
I solved this with this code:
public static byte[] signer(byte[] data, PrivateKey key) throws Exception {
Signature signer = Signature.getInstance("SHA1withRSA/ISO9796-2", "BC");
signer.initSign(key);
signer.update(data);
return signer.sign();
}
SHA1withRSA/ISO9796-2 does the trick.
I'm thankful to David from bouncy castle mailing list for this answer.

supply public key in CERTENROLL request

I want to request a cert (from AD cert server) using a template. I want to supply the public key in the request. Using msft's SDK sample
IX509CertificateRequest iRequest = objEnroll.Request;
// then get the inner PKCS10 request
IX509CertificateRequest iInnerRequest =
iRequest.GetInnerRequest(InnerRequestLevel.LevelInnermost);
IX509CertificateRequestPkcs10 iRequestPkcs10 =
iInnerRequest as IX509CertificateRequestPkcs10;
// create CX500DistinguishedName
CX500DistinguishedName objName = new CX500DistinguishedName();
objName.Encode(subjectName, X500NameFlags.XCN_CERT_NAME_STR_NONE);
// set up the subject name
iRequestPkcs10.Subject = objName;
I think I then need to do some thing like this
iRequestPkcs10.PublicKey.InitializeFromEncodedPublicKeyInfo(xx);
but I dont know what xx is. I have the public key (In a bouncy castle PKCS10 object), but what format must it be in to pass to this function?
You can specify the public key in a number of different formats.
According to MSDN, InitializeFromEncodedPublicKeyInfo takes two parameters: the first is the public key, and the second is an EncodingType enumeration value that specifies the format of the public key you are supplying.

How to get public key from a certificate in iPhone program?

Now I have a certificate which includes a public key, I want to get the public key from it in iPhone SDK programming, and encrypt a string by RSA with the public key. What should I do?
SecKeyRef publicKeyReference = NULL;
NSMutableDictionary* queryPublicKey;
SecItemCopyMatching((CFDictionaryRef)queryPublicKey, (CFTypeRef *)&publicKeyReference);
publicKeyReference - is your public key representation;
queryPublicKey - is your certificate representation;
SecItemCopyMatching - function that allows you to retrieve public key from certificate!