Good day.
I need to teach Windows CryptoAPI to encrypt the message with private (not public) part of the key, and decrypt with public. This is necessary to give users information, that they can read, but can't change.
How it works now:
I get the context
CryptAcquireContext(#Prov, PAnsiChar(containerName), nil, PROV_RSA_FULL, 0)
generate a key pair
CryptGenKey(Prov, CALG_RSA_KEYX, CRYPT_EXPORTABLE, #key)
Encrypt (and the problem is here. "key" - a keypair, and the function uses its public part);
CryptEncrypt(key, 0, true, 0, #res[1], #strLen, buffSize)
Decrypt (the same problem here, it uses the private part of the key)
CryptDecrypt(key, 0, true, 0, #res[1], #buffSize)
Thank you for your attention / help.
Update
Yes, I could use a digital signature and other metods...
The problem is that I need to encrypt one database field and make sure that no one but me can change it. It will be possible to read this field only with the help of my program (till someone decompiles it and get public key). This could be done with symmetrical key and digital signatures, but then i will need to create another field and store another key and so on...
I do hope that we can somehow teach WIN API to do as I want. I know that i can do so with RSA, and I hope that somehow WinAPI supports this feature.
Strictly speaking, when "signing" a message:
the person with the private key decrypts the hash with their private key.
they then send that "decrypted" hash along with the message.
the receiver then encrypts the signature with the public key
If the "encrypted" hash matches the hash of the original message, you know the message has not been altered, and was sent by the person with the private key. The following pseudo-code represents the signing algorithm:
//Person with private key generating message and signature
originalHash = GenerateHashOfMessage(message);
signature = RsaDecrypt(originalHash, privateKey);
//Receiver validating signed message
hash = GenerateHashOfMessage(message);
originalHash = RsaEncrypt(signature, publicKey);
messageValid = (hash == originalHash);
This same mechanism can be used to accomplish what you want. Except you don't care about hashes, you just want to encrypt some (small) amount of data:
//Person with private key
cipherText = RsaDecrypt(plainText, privateKey);
//Person with public key
plainText = RsaEncrypt(cipherText, publicKey);
i'll leave the CryptoAPI calls as an excercise - since i'm still trying to figure out Microsoft's Crypto API.
Encrypting data with the private key and decrypting it with the public key isn't supported because anyone with the "published" public key could decrypt it. What's the value in encrypting it then?
If you want to verify that data hasn't been changed, you will want to sign the data instead. Signing encrypts a hash of the data with the private key. Look at the signing functions.
You may be able to trick out the signing functions to do what you want. I've done this with other implementations, but I haven't tried with the Microsoft CryptoAPI.
Also, note that with RSA encryption, the plain text message cannot be longer than the key. So, if you are using a 2048 bit key, you can only encrypt a message body of up to 256 bytes (minus a few for overhead).
Consider using asymmetric encryption just to pass a symmetric key, and use the symmetric key to encrypt and decrypt any size data.
Update
You may be able to use the CryptSignHash() function for this. Normally, this is used to "sign" a hash, but you can put any data you want into the hash:
Set the hash value in the hash object by using the HP_HASHVAL value of
the dwParam parameter in CryptSetHashParam.
You might be limited to so many bytes if the input is expected to be a SHA1 hash value.
Alternatively, you may wish to consider using OpenSSL. If I recall correctly, it's pretty straight forward to use its RSA signing functions to encrypt with the private key.
Also, I accomplished the same thing using the old (freeware) version of SecureBlackbox. You may be able to find the old free version, but it's not Unicode friendly, so you'll have some conversion to do if you're using a new Delphi. I've done this in the past also, so it's not too difficult.
You may also consider trying out the current SecureBlackbox and purchase it if it works for you.
Otherwise, as you stated, sign it to detect tampering, and encrypt it with a symmetric key that only the program knows in order to obfuscate it.
If they crack your code, anything's fair game anyway.
Related
I am using spring security, and I created a JWT checker. It checks only expiration time so far.
The problem is I expose two different apis, and the callers are also using different public/private keys to generate the jwt(s) I control, which means that I have two different public keys to be able to check the JWTs corresponding to them.
What would be the best way to keep only one function that checks tokens but which also switchs between public keys ?
example :
public class JwtControlValid {
#Value("${public.key.A}") // from application.properties
private String pubKeyA;
#Value("${public.key.B}")
private String pubKeyB;
private RSAPublicKey getPubKey() {
try {
KeyFactory kf = KeyFactory.getInstance("RSA");
// if(caller A)
X509EncodedKeySpec keySpecX509 = new X509EncodedKeySpec(Base64.getDecoder().decode(pubKeyA));
// if (caller B)
X509EncodedKeySpec keySpecX509 = new X509EncodedKeySpec(Base64.getDecoder().decode(pubKeyB));
RSAPublicKey pubKey = (RSAPublicKey) kf.generatePublic(keySpecX509);
return pubKey;
}catch ...
and another function that uses the first one to say if true or false :
public boolean isJwtValid(String jwt) {
try {
Jwts.parser().setSigningKey(getPublicKey()).parseClaimsJws(jwt);
return true;
} catch ....
return false;
Both public keys are RSA public keys
Is there a clean way to switch between public keys depending on the jwt that I receive ?
The problem is I expose two different apis, and the callers are also using different public/private keys to generate the jwt(s) I control, which means that I have two different public keys to be able to check the JWTs corresponding to them.
Yes this is a problem and is not a standard. Having public keys for each client scales bad, and is in general not supported.
Spring out of the box supports trusting single asymmetric key but not multiple because this is not a standard and i do not recommend this approach.
If you want to support multiple keys you should instead be using JWKs which are a number of keys exposed by the issuing service.
What this basically means that the issuer (the server/service) that issues your tokens, has an endpoint, which all resource servers can fetch the public keys needed to verify tokens.
Advantages is that you can rotate keys, you can check against multiple JWKs, it is scalable and secure etc.
If you still want to go down your path which i highly do not recommend then you can for example implement two JwtAuthenticationProvider using its interface.
The you can resolve which one to use by implementing a AuthenticationManagerResolver.
I would highly recommend you read about the entire JWT flow in the spring security official docs and use Nimbus which comes included in spring security instead of JJwt which is just an extra not needed dependency.
I just want to include, writing custom security is never good, and all it takes is one bug in your custom security code and your entire security might be useless. Thats why there are standards, RFC, and established flows. To avoid custom security solutions.
I have a need to encrypt a part of the URL e.g https://www.example.com/resource/{resourceid}.
The resourceid is the element that I want to encyrpt as it may be a sensitive piece of information.
Before returning this URL to the clients, we want to encrypt the resourceid and on the way back (from the client on a subsequent request) we will decrypt the resourceid before processing.
The original resourceid is a string (alphanumeric characters). They are not super-secret, the intent is to make them an "opaque" string before returning them to the caller.
I am unable to figure out if the result of an encryption (symmetric key is what I am after) is URL safe? I can encrypt the resource ID and then do a URL encoding on top and do the reverse on the way back.
However, if the encryption outcome is already URL safe, i won't need to worry about it. I am unable to locate any information that states whether the outcome of an encryption function is URL safe or not.
Any help or pointers would be helpful.
I want to encrypt some values pertaining to a licence code with a secret private key, and then when it's entered in the user's app install it will be decrypted with the public key (stored with the app) to view the encoded data and ensure it was only created by me.
The trouble is it seems that you encrypt with the public key and decrypt with the private key, which is the reverse of what I want.
It's also worth mentioning that the library I'm using called SwiftyRSA only supports encrypting with the public key, and doesn't like it when I use the private key instead. I believe this is because it's being saved to the keychain with kSecAttrKeyClassPublic, because that's what it's expecting, and that causes things to fail.
I have read that the keys are technically interchangeable, but it seems I can't get it to work in my instance. Is this because they public key has a smaller exponent? Is there a way to get the public key to be as "long" as the private key using ssh-keygen, and therefore be able to swap them around? If not, how could I proceed?
The keys aren't always interchangeable (e.g. RSA private keys with CRT parameters) and it is pretty likely that the encryption procedure doesn't protect the key against side channel attacks. You should not use private keys to encrypt, period.
You could use signatures with message recovery if you're really careful.
Otherwise - if you've enough space - you could of course always sign-then-encrypt your license. For this to work (without additional AES encryption) your encryption key pair would have to be quite a bit larger than your signing key though.
I want to generate a key pair on an iPhone such that the private key can only ever be used to sign blocks of data on that particular iPhone.
The SecKeyGeneratePair function looks promising. I can generate a key pair to the keychain (using kSecAttrIsPermanent) and I can disable decryption, derivation and unwrapping with the private key (setting kSecAttrCanDecrypt, kSecAttrCanDerive and kSecAttrCanUnwrap to false).
Two things worry me about key pairs generated with SecKeyGeneratePair:
Is it possible to export the private key outside of the keychain into application memory?
Is it possible to change a key property (e.g. set kSecAttrCanDecrypt to true) after a private key has been created?
This article provides more details (compared to other answers in this thread):
SecGenerateKeyPair(), which is used to generate RSA and ECDSA key pairs, can now be configured to directly store the generated private key in the device’s Keychain (within the Secure Enclave). This means that the private key can be used without ever leaving the device’s Secure Enclave.
And the important addition:
The kSecAttrTokenIDSecureEnclave attribute needs to be used when generating the key pair.
If you don't specify this attribute the private key will be accessible even on iOS9.
To answer the first question, the private key cannot be retrieved according to this source:
One API call, SecKeyGeneratePair(), creates a public and private key.
The public key is returned to the app, and the private key is sent
directly to the Secure Enclave. This private key cannot be retrieved.
More information is available here:
The supported keys are Elliptic Curve P256, the private key is not
extractible in any form, even protected, and the applications are
RawSign and RawVerify.
I have a serialized EC public key - its CKA_EC_PARAMS and CKA_EC_POINT. There's a matching private key on my token. Is there any way to find it?
With an RSA key, I can do a FindObjects with CKA_KEY_TYPE=CKK_PRIVATE_KEY and CKA_MODULUS=. Is there a way to do the same thing with EC keys? According to the PKCS#11 spec, CKA_EC_POINT isn't an attribute for EC Private Keys.
I have a token with support for EC at hand, and it seems that the only way to associate the private and public key will be through the CKA_ID value. No attribute available to test directly the key value.
Actually, even in the case of RSA that's the basic standard method to associate a private and a public key, they ought to be created with identical CKA_ID (that's what the Netscape browser originally did, and everyone copied on that).
They are even some buggy pkcs#11 implementations that won't allow you to read the CKA_MODULUS value of a RSA private key (this is definitevely a bug since the spec explicitly says this value ought to always be public, but it's just one of many bad things frequently happpening with pkcs#11). With them, CKA_ID is the only way even for RSA.