I'm using an RSA library that crashes at certain decrypt operations that contain invalid ciphertext. For security reasons, I don't have access to the RSA key or the ciphertext that are involved in crashes.
In my lab, I tried to submit multiple RSA keys and tweaked ciphertext values to force the crash. I tried with keys from 512 to 4096 bits, and I tweaked a valid ciphertext by changing each bit, prepending garbage, appending garbage, truncating at the tail or truncating at the head. In all cases, the library behaves correctly and reports "invalid ciphertext supplied" instead of crashing as it randomly happens on production.
My last resort is to try unusual RSA keys, for instance with unusual exponents. Do you know any library or tool that allows me to fully customize RSA key generation?
I can call it from C#, Java or C++ (Visual Studio), or it can also be a Windows command-line tool. Sample code or link to reference documentation is highly appreciated.
The CoreFX RSA tests have a couple of unusual keys defined.
DiminishedDPParameters has a DP value which can be expressed with one less byte than usual (when P and Q are both half the width of N/D DP is usually the same size as P or Q). (Generation technique: keep hitting up-enter with openssl genrsa [keysize] | openssl rsa -text -noout until one of the parameters was deficient)
UnusualExponentParameters uses E=0x01B1 instead of E=0x010001 (Generation technique: OpenSSL's RSA_generate_key takes a value for E. Just made one up, but stuck with a prime number for ease of the generator.)
One other thing that makes for an unusual E value is to be larger than 4 bytes (a limitiation of Windows CAPI / .NET RSACryptoServiceProvider). There doesn't seem to be a test with one of those, so here's an inline version. (Crypto disclaimer: This key was generated as an example, and has clearly been exposed to the Internet, don't use it for anything you want to be secret).
$ openssl rsa -in bigexponent.key -text -noout
Private-Key: (2048 bit)
modulus:
00:af:81:c1:cb:d8:20:3f:62:4a:53:9e:d6:60:81:
75:37:23:93:a2:83:7d:48:90:e4:8a:19:de:d3:69:
73:11:56:20:96:8d:6b:e0:d3:da:a3:8a:a7:77:be:
02:ee:0b:6b:93:b7:24:e8:dc:c1:2b:63:2b:4f:a8:
0b:bc:92:5b:ce:62:4f:4c:a7:cc:60:63:06:b3:94:
03:e2:8c:93:2d:24:dd:54:6f:fe:4e:f6:a3:7f:10:
77:0b:22:15:ea:8c:bb:5b:f4:27:e8:c4:d8:9b:79:
eb:33:83:75:10:0c:5f:83:e5:5d:e9:b4:46:6d:df:
be:ee:42:53:9a:ef:33:ef:18:7b:77:60:c3:b1:a1:
b2:10:3c:2d:81:44:56:4a:0c:10:39:a0:9c:85:cf:
6b:59:74:eb:51:6f:c8:d6:62:3c:94:ae:3a:5a:0b:
b3:b4:c7:92:95:7d:43:23:91:56:6c:f3:e2:a5:2a:
fb:0c:14:2b:9e:06:81:b8:97:26:71:af:2b:82:dd:
39:0a:39:b9:39:cf:71:95:68:68:7e:49:90:a6:30:
50:ca:77:68:dc:d6:b3:78:84:2f:18:fd:b1:f6:d9:
ff:09:6b:af:7b:eb:98:dc:f9:30:d6:6f:cf:d5:03:
f5:8d:41:bf:f4:62:12:e2:4e:3a:fc:45:ea:42:bd:
88:47
publicExponent: 8589935681 (0x200000441)
privateExponent:
64:af:9b:a5:26:24:83:da:92:b5:3f:13:43:9f:d0:
ef:13:01:2f:87:9a:bc:03:cb:7c:06:f1:20:99:04:
f3:52:c1:f2:23:51:9d:c4:8b:fa:ee:bb:51:1b:0d:
95:5f:61:67:b5:0e:03:4f:ea:2a:bc:59:0b:4e:a9:
fb:f0:c5:1f:9f:fe:a1:6f:79:27:ae:68:1c:bf:73:
58:45:2b:ca:29:d5:87:05:e0:ca:a1:06:01:3b:09:
a6:f5:f5:91:14:98:d2:c4:fd:69:15:58:54:88:e5:
f3:ad:89:83:6c:93:c8:77:5a:fa:b4:d1:3c:20:14:
26:6b:e8:ee:6b:8a:a6:6c:9e:94:2d:49:34:66:c8:
e3:a3:70:f8:e6:37:8c:e9:5d:63:7e:03:67:36:70:
be:4b:ca:ce:5f:cd:ad:d2:38:d9:f3:2c:a3:5d:e8:
45:77:6a:c4:bf:36:11:88:12:32:8c:49:3f:91:c2:
5a:9b:d4:26:72:d0:af:af:de:0a:f7:e6:19:07:8d:
48:b4:85:ef:91:93:3d:dc:ff:b5:45:87:b8:f5:12:
d2:23:c8:18:94:e9:17:84:98:2f:3c:5c:65:87:13:
51:f4:65:5a:b0:23:c4:ad:99:b6:b0:3a:96:f9:04:
6c:e1:24:a4:71:e8:28:f0:5f:8d:b3:bc:7c:cc:f2:
d1
prime1:
00:e4:3a:38:26:a9:72:04:ae:3c:d8:64:9a:84:db:
4b:bf:07:25:c4:b0:8f:8c:43:84:05:57:a0:cd:04:
e3:13:af:6d:04:60:dd:e6:9c:dc:50:8a:d0:43:d7:
25:14:da:7a:66:bc:91:8c:d9:62:4f:48:56:44:b9:
de:ea:b2:be:0e:11:29:56:d4:72:cf:0f:d5:1f:80:
fd:33:87:2d:2d:cc:56:2a:05:88:b0:12:e8:c9:0c:
e7:d2:54:b9:47:92:c6:e7:a0:2b:3c:ca:a1:50:e6:
7a:64:37:7a:cc:49:47:9a:d5:eb:55:54:93:b2:10:
0c:b0:41:09:56:f7:d7:3b:f5
prime2:
00:c4:dd:2d:7a:dd:6c:a5:07:40:d3:97:3f:40:c4:
de:bd:ba:b5:1f:7f:51:81:ab:ae:72:6c:32:59:6a:
3e:dd:0a:ee:44:da:ad:dd:8a:9b:7a:86:4c:4f:fd:
ae:00:c4:cb:1f:10:17:7b:a0:1c:04:66:f8:12:d5:
22:61:0f:8c:45:43:f1:c3:ef:57:9f:a9:e1:3a:e8:
da:1a:4a:8d:ae:30:78:61:d2:ce:ac:03:56:02:79:
b6:1b:65:14:98:98:83:fe:86:c5:c7:42:0d:31:28:
38:fc:2f:70:be:d5:9b:52:29:65:42:01:88:26:64:
ce:fa:38:b4:8a:37:23:e9:cb
exponent1:
09:ec:f1:51:f5:cd:d2:c9:e6:e5:26:82:36:4f:a5:
b4:ed:09:4f:62:2e:40:31:bf:46:b8:51:35:8a:58:
4d:cc:b5:32:8b:0b:d9:b6:35:89:18:3f:49:15:93:
d2:a3:ac:ad:14:e0:aa:cd:a1:f1:81:b5:c7:d9:3c:
57:ed:26:e6:2c:9f:c2:6a:f3:7e:4a:06:44:ec:e8:
2a:7b:a8:ae:d8:8f:f1:d8:e9:c5:6c:c6:63:85:cd:
b2:44:eb:3d:57:d1:7e:6a:d4:20:b1:9c:9e:2b:ee:
18:19:2b:81:62:65:b7:4d:a5:5f:a3:82:5f:92:2d:
9d:8e:83:5b:76:bf:30:71
exponent2:
00:89:b3:3b:69:57:89:17:4b:88:36:8c:49:46:39:
d4:d3:26:72:24:57:2a:40:b2:fe:61:91:03:84:22:
8e:3d:bd:11:ee:d9:04:0c:d0:39:77:e9:e0:d7:fc:
8b:fc:4b:f4:a9:32:83:52:9f:f1:d9:65:90:b1:8f:
4e:ab:ef:03:03:79:4f:29:3e:88:dc:76:1b:3e:23:
af:ec:b1:9f:29:f8:a4:d2:a9:05:8b:71:4c:f3:f4:
d1:07:33:f1:3e:a7:2b:bf:1f:be:c8:d7:1e:10:6d:
0c:e2:11:5f:3a:d2:de:02:03:25:c3:87:9a:09:1c:
41:3c:d6:39:7f:83:b3:cb:89
coefficient:
7c:57:ed:74:c9:17:6f:ba:76:c2:31:83:20:25:15:
06:2c:66:4d:4d:49:ff:3e:03:70:47:a3:09:da:10:
f1:59:0c:e0:1b:7a:1c:d1:a4:32:6d:c7:58:83:df:
f9:31:10:ab:06:5a:ae:d1:40:c9:b9:81:76:a8:81:
08:09:ad:ec:75:e8:67:64:a0:95:15:97:ef:46:7f:
a8:fd:50:91:81:cd:2e:49:1e:43:be:41:08:4e:5b:
e1:b5:62:ee:76:e9:f9:2c:9a:b1:e5:ae:ad:9d:29:
1a:63:37:e4:de:85:bd:e6:7a:0d:72:b4:e5:5a:dc:
f2:07:f7:a5:a5:22:5e:15
Related
I'm trying to use a public key of a user to encrypt a string in a sort of pgp fashion, but I keep getting the error:
bignum routines:BN_mod_inverse:no inverse
I've looked around and I cannot find anything specific as to what I'm doing wrong. I've looked around for .NET core information, but I cannot seem to find anything relevant.
I'm using the following code:
byte[] publicKey = Encoding.UTF8.GetBytes(key);
RSA rsa = RSA.Create();
RSAParameters RSAKeyInfo = new RSAParameters();
RSAKeyInfo.Modulus = publicKey;
RSAKeyInfo.Exponent = new byte[]{1,0,1};
rsa.ImportParameters(RSAKeyInfo);
var encrypted = rsa.Encrypt(Encoding.UTF8.GetBytes(user.challenge.text), RSAEncryptionPadding.Pkcs1);
It's entirely possible I'm going about this entirely wrong, so any thoughts or suggestions would be great!
Your overall structure (build RSAParameters, call ImportParameters, call Encrypt) is valid, which suggests that your error is in Modulus recovery.
If your Modulus is input as a string, it's likely encoded as (most to least)
Base64 (Convert.FromBase64String)
Hex (May need a manual parser)
UTF-8
UTF-8 is really unlikely, since the Modulus value can contain bytes whose value are 0 (and other invalid/unexpected UTF-8 sequences). While all even-length byte sequences encoded as hex can be validly decoded as Base64, it's extraordinarily unlikely that you'd misinterpret them given two or three different inputs.
Other noteworthy things:
RSA is IDisposable, you should put it in a using statement to ensure resources free up earlier when you are done with them.
The Exponent is usually 0x010001, but that isn't required. Unless you have a guaranteed constraint on it, you should be serializing it, too.
And if it is guaranteed to always be 0x010001, why make a new one each time? Save it as a static field and make the GC's job easier.
As Maarten said, RSA-ENC-PKCS1 is susceptible to a padding oracle attack, so (especially if your data is over the wire) you should use OAEP.
In the context of .NET, OaepSHA1 has the best support (all inbox providers). OAEP with a SHA-2 algorithm is only supported by RSACng (or the opaque RSA.Create() on Windows).
I got an application that in C#, using RSACryptoServiceProvider, I load a public key from an XML and then I'm encrypting a hash value and saving it.
In another application, I load the private key and then I'm able to decrypt the information correctly.
The problem is that I want to make quick tests to see if everything's ok.
From MSDN,
The security of RSA derives from the fact that, given the public key { e, n }, it is computationally infeasible to calculate d, either directly or by factoring n into p and q. Therefore, any part of the key related to d, p, or q must be kept secret.
so the most important parameters of the private key are the exponent and the primes (D, P, Q).
My test was to modify the private key before loading it. First, I changed one character in the first prime and I got a bad key. Same when just modifying one character in the second prime.
But when I modified one character in the exponent, it was still able to correctly decode it. So my question is, which things can be changed from the private key and still be able to decode, and which are essential?
While Modulus, Exponent, and D are all that are required to do RSA technically, very few implementations actually use D, because it's much more efficient to do RSA via the Chinese Remainder Theorem.
While the Windows CAPI (used by RSACryptoServiceProvider) will roundtrip any value of D you import, it doesn't actually use it. Windows CNG (used by RSACng) requires that D be provided on import of a private key, then promptly throws it away, recomputing it on export (or import, I suppose).
You can see that last quirk by generating an RSA key with OpenSSL (which generates d via phi (which is the form Wikipedia mentions) and importing it into CNG, which when exporting has replaced d with the calculation based on lambda (LCM(p-1, q-1)).
Anyways, what all this amounts to is that while "changing D is bad" it can, in practice, just be ignored by the library doing the actual math; and that seems to be the case here. But you shouldn't do it, because it might not interoperate well after going via a PFX or other private key transfer mechanism.
X9ECParameters curve = NistNamedCurves.GetByName("P-521");
ECDomainParameters ecparam = new ECDomainParameters(curve.Curve, curve.G, curve.N, curve.H, curve.GetSeed());
ECKeyPairGenerator generator = new ECKeyPairGenerator();
generator.Init(new ECKeyGenerationParameters(ecparam, new SecureRandom()));
AsymmetricCipherKeyPair ackp1 = generator.GenerateKeyPair();
AsymmetricCipherKeyPair ackp2 = generator.GenerateKeyPair();
then,
ECDHWithKdfBasicAgreement agreement = new ECDHWithKdfBasicAgreement("2.16.840.1.101.3.4.42", new ECDHKekGenerator(DigestUtilities.GetDigest("SHA256")));
agreement.Init(ackp1.PrivateKey);
BigInteger agInt = agreement.CalculateAgreement(ackp2.PublicKey);
byte[] aeskey = agInt.ToByteArrayUnsigned();
This goes through without generating any errors and I verified that the "aeskey" is the same when I swap in the other pair of public/private keys.
I found zero examples of this kind of usage with google.
The code seems correct to me, bu having to provide the Der OID for AES256 (instead of the string "AES256", which bombs in CalculateAgreement) makes me suspicious that I am doing something wrong.
this was reposted from This question on crypto.stackexchange.
You seem to be heading in the right direction though I'm not sure your OID is correct. It looks very suspicious to me, a quick internet search did not show up any expected results.
According to RFC 2631:
algorithm is the ASN.1 algorithm OID of the CEK wrapping algorithm
with which this KEK will be used. Note that this is NOT an
AlgorithmIdentifier, but simply the OBJECT IDENTIFIER. No
parameters are used.
So the use of an OID is correct, but the OID itself may not be. I would expect an OID that indicates e.g. AES in CBC or GCM mode. This won't show up if you use an invalid OID on both sides of course, it is only used to generate your key, not when you actually use it.
Note that the code of Bouncy Castle seems to be vulnerable to a bug that was also in the Java DH code: a BigInteger is always encoded in the minimal number of bytes. However, the key generated by any normal key agreement is a specific number of bytes, including initial 00 valued bytes. This means that just calling BigInteger.ToByteArray will generate the wrong number of bytes (or an illegal value) once in about 256 bytes as leading zero's will be lost during the conversion. Again, this won't make any differences in operation during testing against identical code on the same system. But the DH used against other systems will fail now and then (I've reported this to Bouncy for Java and it has been confirmed and then fixed in Bouncy 1.50)...
ECDHWithKdfBasicAgreement is a little awkward since it's a port of something that only exists in the JCE parts of the Java build. As #owlstead points out you need to deal with the BigInteger/byte[] conversion. In this case, with latest code, you can use:
int keyLen = GeneratorUtilities.GetDefaultKeySize(algorithm) / 8;
byte[] key = BigIntegers.AsUnsignedByteArray(keyLen, agInt);
or of course, just pad it out to the size you known you need. I think the AES256 thing is fixed in latest code too. Code is now on github (https://github.com/bcgit/bc-csharp), but a new beta build of C# is (finally) a mere day or two away also.
Is there any way to perform private key encryption in C#?
I know about the standard RSACryptoServiceProvider in System.Security.Cryptography, but these classes provide only public key encryption and private key decryption. Also, they provide digital signature functionality, which uses internally private key encryption, but there are not any publicly accessible functions to perform private key encryption and public key decryption.
I've found this article on codeproject, which is a very good start point for performing this kind of encryption, however, I was looking for some ready-to-use code, as the code in the article can hardly encrypt arbitrary-long byte arrays containing random values (that means any values, including zeroes).
Do you know some good components (preferably free) to perform private key encryption?
I use .NET 3.5.
Note: I know this is generally considered as bad way of using asymmetric encryption (encrypting using private key and decrypting using public key), but I just need to use it that way.
Additional Explanation
Consider you have
var bytes = new byte[30] { /* ... */ };
and you want to use 2048bit RSA to ensure no one have changed anything in this array.
Normally, you would use digital signature (ie. RIPEMD160), which you then attach to the original bytes and send over to the receiver.
So, you have 30 bytes of original data, and additional 256 bytes of digital signature (because it is a 2048bit RSA), which is overall of 286 bytes. Hovewer, only 160 bits of that 256 bytes are actually hash, so there is exactly 1888 bits (236 bytes) unused.
So, my idea was this:
Take the 30 bytes of original data, attach to it the hash (20 bytes), and now encrypt these 50 bytes. You get 256 bytes long message, which is much shorter than 286 bytes, because "you were able to push the actual data inside the digital signature".
ECDSA Resources
MSDN
Eggheadcafe.com
c-plusplus.de
MSDN Blog
Wiki
DSA Resources
CodeProject
MSDN 1
MSDN 2
MSDN 3
Final Solution
If anyone is interested how I've solved this problem, I'm going to use 1024bit DSA and SHA1, which is widely supported on many different versions of Windows (Windows 2000 and newer), security is good enough (I'm not signing orders, I just need to ensure that some child can't crack the signature on his iPhone (:-D)), and the signature size is only 40 bytes long.
What you are trying to design is known as a "Signature scheme with message recovery".
Designing a new signature scheme is hard. Designing a new signature scheme with message recovery is harder. I don't know all the details about your design, but there is a good chance that it is susceptible to a chosen message attack.
One proposal for signature schemes with message recovery is RSA PSS-R. But unfortunately, this proposal is covered with a patent.
The IEEE P1363 standarization group, once discussed the addition of signature schemes with message recovery. However, I'm not sure about the current state of this effort, but it might be worth checking out.
Your Public key is a sub-set of your private key. You can use your private key as a public key as it will only use the components of the full key it requires.
In .NET both your private & public keys are stored in the RSAParameters struct. The struct contains fields for:
D
DP
DQ
Exponent
InverseQ
Modulus
P
Q
If you're at the point where the data is so small that the digital signature is huge in comparison, then you have excess signature. The solution isn't to roll your own algorithm, but to cut down what's there. You definitely don't want to try to combine a key with the hash in an amateurish way: this has been broken already, which is why we have HMAC's.
So here's the basic idea:
Create a session key using a cryptographically strong RNG.
Transmit it via PKE.
Use the session key to generate an HMAC-SHA1 (or HMAC-RIPEMD160, or whatever).
If the size of the hash is absurdly large for the given data, cut it in half by XORing the top with the bottom. Repeat as needed.
Send the data and the (possibly cut-down) hash.
The receiver uses the data and the session key to regenerate the hash and then compares it with the one transmitted (possibly after first cutting it down.)
Change session keys often.
This is a compromise between the insanity of rolling your own system and using an ill-fitting one.
I'm wide open to constructive criticism...
I get it now, after reading the comments.
The answer is: don't do it.
Cryptographic signature algorithms are not algorithms from which you can pick and choose - or modify - steps. In particular, supposing a signature sig looks something like encrypt(hash), orig + sig is not the same as encrypt(orig + hash). Further, even outdated signature algorithms like PKCS v1.5 are not as simple as encrypt(hash) in the first place.
A technique like the one you describe sacrifices security for the sake of cleverness. If you don't have the bandwidth for a 256 byte signature, then you need one of:
a different algorithm,
more bandwidth, or
a smaller key.
And if you go with (1), please be sure it's not an algorithm you made up! The simple fact is that crypto is hard.
I want to encrypt a string and embed it in a URL, so I want to make sure the encrypted output isn't bigger than the input.
Is AES the way to go?
It's impossible to create any algorithm which will always create a smaller output than the input, but can reverse any output back to the input. If you allow "no bigger than the input" then basically you're just talking isomorphic algorithms where they're always the same size as the input. This is due to the pigeonhole principle.
Added to that, encryption usually has a little bit of padding (e.g. "to the nearest 8 bytes, rounded up" - in AES, that's 16 bytes). Oh, and on top of that you're got the issue of converting between text and binary. Encryption algorithms usually work in binary, but URLs are in text. Even if you assume ASCII, you could end up with an encrypted binary value which isn't ASCII. The simplest way of representing arbitrary binary data in text is to use base64. There are other alternatives which would be highly fiddly, but the general "convert text to binary, encrypt, convert binary to text" pattern is the simplest one.
Simple answer is no.
Any symmetric encryption algorithm ( AES included ) will produce an output of at minimum the same but often slightly larger. As Jon Skeet points out, usually because of padding or alignment.
Of course you could compress your string using zlib and encrypt but you'd need to decompress after decrypting.
Disclaimer - compressing the string with zlib will not guarantee it comes out smaller though
What matters is not really the cipher that you use, but the encryption mode that you use. For example the CTR mode has no length expansion, but every encryption needs a new distinct starting point for the counter. Other modes like OFB, CFB (or CBC with ciphertext stealing) also don't need to be padded to a multiple of the block length of the cipher, but they need an IV. It is unclear from your question if there is some information available from which an IV could be derived pseudorandomly an if any of these modes would be appropriate. It is also unclear if you need authentication, or if you need semantic security> i.e. is it a problem if you encrypt the same string twice and you get the same ciphertext twice?
If we are talking about symetric encription to obtain the original encrypted string from a cyphered one it is not possible. I think that unless you use hashes (SHA1, SHA256...) you will never obtain a cyphered string smaller than the original text. The problem with hashes is that they are not the solution for retrieving the original string because they are one way encryption algorithms.
When using AES, the output data will be rounded up to have a specific length (e.g a length divisible trough 16).
If you want to transfer secret data to another website, a HTTP post may do better than embedding the data into the URL.
Also just another thing to clarify:
Not only is it true that symmetric encryption algorithms produce an output that is at least as large as the input, the same is true of asymmetric encryption.
"Asymmetric encryption" and "cryptographic hashes" are two different things.
Asymmetric encryption (e.g. RSA) means that given the output (i.e. the ciphertext), you can get the input (i.e. the plaintext) back if you have the right key, it's just that decrypting requires a different key than the key used for encrypting. For asymmetric encryption, the same "pigeonhole principle" argument applies.
Cryptographic hashes (e.g. SHA-1) mean that given the output (i.e. the hash) you can't get the input back, and you can't even find a different input that hashes to the same value (assuming the hash is secure). For cryptographic hashes, the hash can be shorter than the input. (In fact the hash is the same size regardless of the length of the input.
And also one more thing: In any secure encryption system the ciphertext will be longer than the plaintext. This is because there are multiple possible ciphertexts that any given plaintext could encrypt to (e.g. using different IVs.) If this were not the case then the cipher would leak information because if two identical plaintexts were encrypted, they would encrypt to identical ciphertexts, and an adversary would then know that the plaintexts were the same.