I want to know if RSA signatures are unique for a data.
Suppose I have a "hello" string. The method of computing the RSA signature is firstly to get the sha1 digest(these are , I know, unqiue for data), then add a header with OID and padding scheme mentioned and do some mathematical jiggle to give the signature.
Now assuming padding is same, will the signature generating by openSSL or Bouncy Castle be same?
If yes, my only fear is, won't it be easy to get back the "text"/data??
I actaully tried to do an RSA signature of some data and the signatures from OpenSSL and BC was different. I repeated it but got same signature again and again for each of them. I realized that the two signatures of the methods were different because of the difference in padding. However I am still not sure why the signatures of each of the libs are same all the time I repeat them. Can somebody please give an easy explanation?
The "usual" padding scheme, described in PKCS#1 as the "old-style, v1.5" padding, is deterministic. It works like this:
The data to sign is hashed (e.g. with SHA-1).
A fixed header is added; that header is actually an ASN.1 structure which identifies the hash function which was just used to process the data.
Padding bytes are added (on the left): 0x00, then 0x01, then some 0xFF bytes, then 0x00. The number of 0xFF bytes is adjusted so that the resulting total length is exactly the byte length of the modulus (i.e. 128 bytes for a 1024-bit RSA key).
The padded value is converted to an integer (which is less than the modulus), which goes through the modular exponentiation which is at the core of RSA. The result is converted back to a sequence of bytes, and that's the signature.
All these operations are deterministic, there is no random, hence it is normal and expected that signing the same data with the same key and the same hash function will yield the same signature ever and ever.
However there is a slight underspecification in the ASN.1-based fixed header. This is a structure which identifies the hash function, along with "parameters" for that hash function. Usual hash functions take no parameters, hence the parameters shall be represented with either a special "NULL" value (which takes a few bytes), or be omitted altogether: both representations are acceptable (although the former is supposedly preferred). So, the raw effect is that there are two versions of the "fixed header", for a given hash function. OpenSSL and Bouncycastle do not use the same header. However, signature verifiers are supposed to accept both.
PKCS#1 also describes a newer padding scheme, called PSS, which is more complex but with a stronger security proof. PSS includes a bunch of random bytes, so you will get a distinct signature every time.
Signatures are not a privacy mechanism; it's not considered a problem if you can get the plaintext back out. If your message must be kept secret, then encrypt as well as sign.
Nevertheless, remember that RSA signatures are created using a signer's private key. Given such a signature, you can use the signer's public key to "undo" the RSA transform (raise the message's signature to e, mod n) and get out the SHA1 or other hash value that was provided as its input. You still can't undo the hash function to get the input plaintext corresponding to a signature that has become detached from its message.
RSA for encryption is a different matter. Padding methods for encryption here do include random data in order to defeat traffic analysis.
This is why you add a salt/initialisation vector on top of your key. That way it shouldn't be possible to tell which records came from the same plaintext.
Related
I'm writing a utility to convert md5 (or sha1) digest to a distinguishable image, something like ssh-keygen -lv. Usually, similar messages can have digests very different, but hackers can modify the message bit by bit to try to get a similar but still different md5 digest to mock the original one. When matching is done by machine, the trick will certainly fail. But when matching is done by human eye, user could be fooled.
To avoid of such trick, the convert program can generate the image from a modified digest as follow:
image = generateImage( md5(md5 + Random_Secret) )
The Random_Secret will reshape the digest, the similarity introduced by hacker will be removed after the transformation.
Now comes the question, since the final md5() take input of another md5 variable, which is only 128-bit length, (here ignore the Random_Secret which is a constant in all) is it safe to generate enough different values for feeding generateImage()?
Question also for other digest algorithms: sha1, etc.
A hash function should have the following properties, among others:
In cryptography, the avalanche effect is the desirable property of cryptographic algorithms, typically block ciphers and cryptographic hash functions, wherein if an input is changed slightly (for example, flipping a single bit), the output changes significantly (e.g., half the output bits flip).
see https://en.wikipedia.org/wiki/Avalanche_effect
Thus, hackers should not be able to slightly modify the message to obtain a similar digest unless the hash function is broken. Also it should not be possible to create a message that results in a specific hash value (so it should resist preimage attacks, see https://en.wikipedia.org/wiki/Preimage_attack).
md5 is cryptographically broken
So would the use of a simple md5 hash already be sufficient?
No. Although md5 is a widely used hash function, it has the problem that it is cryptographically broken and therefore insecure.
One basic requirement of any cryptographic hash function is that it should be computationally infeasible to find two distinct messages that hash to the same value. MD5 fails this requirement catastrophically; such collisions can be found in seconds on an ordinary home computer.
see https://en.wikipedia.org/wiki/MD5
Therefore, it is generally recommended to stop using md5 in a cryptographic context.
Since such a collision would result in the same hash in the first inner hash operation in your approach, the repeated hash with an additional constant random secret would also be the same. This means that this attack can successfully exchange the message or file with a different one.
The other hash algorithm you mentioned, SHA-1, is also cryptographically broken.
In this context, there is a worth reading article from Arstechnica from 2008 about the exploitation of md5 collisions to create bogus CA intermediate certificates.
Example of a hash collision
Finally to illustrate a hash collision, here are two .jpg files with the same md5 hash. The collision was created using the following open source project published on Github: https://github.com/cr-marcstevens/hashclash.
The following small Python program writes the files yes.jpg and no.jpg into the current directory to be able to compare the files visually, and then calculates the md5 hash for them - which results in exactly the same value for both files.
import binascii
import hashlib
yes = b'ffd8ffe000104a46494600010101012c012c0000ffe100a04578696600004d4d002a000000080005011a0005000000010000004a011b0005000000010000005201280003000000010002000001320002000000140000005a87690004000000010000006e000000000000012c000000010000012c00000001323032323a31313a31392032323a35373a3133000003a00100030000000100010000a00200030000000100800000a0030003000000010080000000000000ffe10c3b687474703a2f2f6e732e61646f62652e636f6d2f7861702f312e302f003c3f787061636b657420626567696e3d22efbbbf222069643d2257354d304d7043656869487a7265537a4e54637a6b633964223f3e203c783a786d706d65746120786d6c6e733a783d2261646f62653a6e733a6d6574612f2220783a786d70746b3d22584d5020436f726520352e352e30223e203c7264663a52444620786d6c6e733a7264663d22687474703a2f2f7777772e77332e6f72672f313939392f30322f32322d7264662d73796e7461782d6e7323223e203c7264663a4465736372697074696f6e207264663a61626f75743d222220786d6c6e733a64633d22687474703a2f2f7075726c2e6f72672f64632f656c656d656e74732f312e312f2220786d6c6e733a70686f746f73686f703d22687474703a2f2f6e732e61646f62652e636f6d2f70686f746f73686f702f312e302f2220786d6c6e733a786d703d22687474703a2f2f6e732e61646f62652e636f6d2f7861702f312e302f2220786d6c6e733a786d704d4d3d22687474703a2f2f6e732e61646f62652e636f6d2f7861702f312e302f6d6d2f2220786d6c6e733a73744576743d22687474703a2f2f6e732e61646f62652e636f6d2f7861702f312e302f73547970652f5265736f757263654576656e7423222070686f746f73686f703a436f6c6f724d6f64653d2233222070686f746f73686f703a49434350726f66696c653d22735247422049454336313936362d322e312220786d703a4d65746164617461446174653d22323032322d31312d31395432323a35373a31332b30313a30302220786d703a4d6f64696679446174653d22323032322d31312d31395432323a35373a31332b30313a3030223e203c64633a7469746c653e203c7264663a416c743e203c7264663a6c6920786d6c3a6c616e673d22782d64656661756c74223e7965733c2f7264663a6c693e203c2f7264663a416c743e203c2f64633a7469746c653e203c786d704d4d3a486973746f72793e203c7264663a5365713e203c7264663a6c6920786d704d4d3a616374696f6e3d2270726f64756365642220786d704d4d3a736f6674776172654167656e743d22416666696e6974792044657369676e657220312e31302e352220786d704d4d3a7768656e3d22323032322d31312d31395432303a34343a33372b30313a3030222f3e203c7264663a6c692073744576743a616374696f6e3d2270726f6475636564222073744576743a736f6674776172654167656e743d22416666696e6974792050686f746f20312e31302e35222073744576743a7768656e3d22323032322d31312d31395432323a35373a31332b30313a3030222f3e203c2f7264663a5365713e203c2f786d704d4d3a486973746f72793e203c2f7264663a4465736372697074696f6e3e203c2f7264663a5244463e203c2f783a786d706d6574613e2020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020203c3f787061636b657420656e643d2277223f3effed005050686f746f73686f7020332e30003842494d04040000000000171c015a00031b25471c0200000200041c02050003796573003842494d0425000000000010acd1c50e9eee8829b1943af6ed4ce40dffe202644943435f50524f46494c45000101000002546c636d73043000006d6e74725247422058595a2007e6000b0013000f00240031616373704150504c0000000000000000000000000000000000000000000000000000f6d6000100000000d32d6c636d7300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b64657363000001080000003e63707274000001480000004c77747074000001940000001463686164000001a80000002c7258595a000001d4000000146258595a000001e8000000146758595a000001fc000000147254524300000210000000206754524300000210000000206254524300000210000000206368726d00000230000000246d6c756300000000000000010000000c656e5553000000220000001c0073005200470042002000490045004300360031003900360036002d0032002e003100006d6c756300000000000000010000000c656e5553000000300000001c004e006f00200063006f0070007900720069006700680074002c002000750073006500200066007200650065006c007958595a20000000000000f6d6000100000000d32d736633320000000000010c42000005defffff325000007930000fd90fffffba1fffffda2000003dc0000c06e58595a200000000000006fa0000038f50000039058595a20000000000000249f00000f840000b6c358595a2000000000000062970000b787000018d9706172610000000000030000000266660000f2a700000d59000013d000000a5b6368726d00000000000300000000a3d70000547b00004ccd0000999a0000266600000f5cffdb004300100b0c0e0c0a100e0d0e1211101318281a181616183123251d283a333d3c3933383740485c4e404457453738506d51575f626768673e4d71797064785c656763ffdb0043011112121815182f1a1a2f634238426363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363ffc00011080080008003012200021101031101ffc4001b00010002030101000000000000000000000005060102030407ffc40035100002020102040306030803000000000000010203040511122131410651611314223271e152a1b116344262818291926372f0ffc4001a010100020301000000000000000000000000020501030406ffc40023110101010002010401050000000000000000010203110412213151131432414252ffda000c03010002110311003f00fa00000000000000000020752d7ecc3cf9515d519c21b716ef9b64be1e5579b8d1beaf965d9f54fc884de756c8d58e6c6f5732fbc7700136d000000000000000000000d6728c20e5269452ddb7d84e71ae0e73928c62b76df62a7aceb52cc6e9a1b8d0babef3fb1af939262775a39f9f3c39eefca3b3eff79cdbae5d2726d7d3b161f09efee97f971adbfc1572efa2e27b9e9d5c24b69cbe397d59cbc12eb7ea56f852eb9bd4f7800ee5c800000000000000006b39c6b839cda8c62b76df636203c4da82854b0eb97c53e73dbb2f223bd4c67bad5cdc938b175517abead667d8eb8371c78be4bf17ab23002b35ababdd506f7adebd5a7b349a617ea745767cae5bbf5db99793e769b8b4e2da6b9a6892a75ecfaa1c3ed2334bbce3bb37f0f2e713aaebf17c8c714b351730543f6933ff00e2ff005fb9df17c4d72b12caae1283eae0b668df3c8c576cf3b8ade96806232528a945ee9add1937bb0000000003593e18b93e896e6c70cd970e15f25dab97e82b1abd4b555cad7f36f93f67354c37e4a2b9ff00922e5294e4e5393949f56deed980556b5ad7cd79cdf26b77bd5ec001140000036842564e3082de527b25ea6a7b747ba18fa9d13b229c78b6fa6fcb72599dd92a5992ea4abae3d6eac7aeb7d6314bf23a18325abd249d4e800064000038e5c78b12e8f9c24bf23b1ceffddecffabfd0c5f8475fb6be7a002a5e68000000003dda3e27be6a35d6e4928fc6fd52ec78493f0f46c7ab54e09b4b7e27e4b627c73bd46de292f2665fb5c8c805a3d100000000073bd6f8f625de2ff43a180c59dce9f3a05b323c378b75b2b236595f13df65b34709785a1fc39525f5815f7c7da92f85cd3f85681607e16b3b6547fd3ee693f0be42f92faa5f54d18fc3c9f48df179a7f5410261f86f3974753feefb185e1bce6f9ba97f77d88fe2dfd23fa7e5ff00351318b949462b76dec92ee5f30712ac3c78d75414797c4fbb7ea47699a057896abaf9ab6c8fca92e4993475f0715c7bd58f87e3de3ef5b9ee000e8778000000000000693b6baf6f6938c37e9c4f6dcdcf06b3a6c354d3ecc796ca7f3572fc32ec07b6528c22e53928c5756dec8d1e4d1149caead26b75bc97329d56466eb8b1b45ba33add127ef537dd45f2ff00de7b1d3c495e1d1af69f5e45129e2c28e17557befb7c5b6db35e805b619145925185d5ca4fa2524d8b3229a5a56dd5c1be8a524b72bda22d127a941e0e9f914df14dc676716cb96cfac9f99199355387a9e5cb5ec0bef8dd6375e4464f64bb6dcfe9f402f09a6b74f74cc90fe198515e97c38b992caa78df0b947670fe5dbf3fea4c000000000000000000000109a5e064e3ebfa964db5f0d376dece5c49effd3a9c75ac4d45ebd899f838aaf54d6d34e718addefe6fd4b0802230f335ab32ab8656995d34b7f14d5d17b72f2dcf1463afe9d75f54295a8d1649b84ecb79c7d1eecb20021bc37a65fa7635d2c9e18db7d9c6e10e90f426400000000003ffd9c4b3388e3f1f25df001a62f92687ecd5a5e418c4696dc90500000000189c71a5bddcd3a76b848dfd728e06107cfc7c58590457b174269b47a819677378d674e75717b38cb4c1d899c835393e77ef8ac23a6906f23d7a1ca0c44587a1a53265b96bedce9336efec51ff4915b409013aaceb0063ca664f64f24b8aa1845f0ad97a608304e6bdd2dbf22402569ab6d864ed484f1328cba836c425d8bf1a3c5cd8fd2a4e73fe5cb6359576f0e08597d74cc34405281ff880335050a3aecd75509ea44f847da805e2e5f2b51f05af0d1832d8905e7a7dd7a2227c412e241bf800fdb09c97bc11f6c412842e7102a793a894527be3a7ab503784dc33138fd2b2fc13ff48af9abd222c17c218f4d79f2b4a736622d67efad4e6e2794eeca6cae5983eb5eef36704a91578ec5f82c5dd9efb87e5e51b289c05eb6aefa9ca7b4e252839d299dcb24711aa196fd5b6a9af9147e137e1df9e778ccb8e8eede6a4814e59c957402cd6684eabf560277fe6195d635331a55005dd639de303c51d5ca468e6de7d5718f48a00dc4cce9476feda338a6b65bf702c368df0cdc71676b44c829a1054a3c7585dc3927bd9dca3660b6b4f078a85663f7ad5e0157412dd0d17aa43f5983441a66ed6900672f35bf14515698b98d173b7bdfc639c5cbcab9eec9ab30bb3f055536f'
no = b'ffd8ffe000104a46494600010101012c012c0000ffe100a04578696600004d4d002a000000080005011a0005000000010000004a011b0005000000010000005201280003000000010002000001320002000000140000005a87690004000000010000006e000000000000012c000000010000012c00000001323032323a31313a31392032323a35363a3331000003a00100030000000100010000a00200030000000100800000a0030003000000010080000000000000ffe10c3b687474703a2f2f6e732e61646f62652e636f6d2f7861702f312e302f003c3f787061636b657420626567696e3d22efbbbf222069643d2257354d304d7043656869487a7265537a4e54637a6b633964223f3e203c783a786d706d65746120786d6c6e733a783d2261646f62653a6e733a6d6574612f2220783a786d70746b3d22584d5020436f726520352e352e30223e203c7264663a52444620786d6c6e733a7264663d22687474703a2f2f7777772e77332e6f72672f313939392f30322f32322d7264662d73796e7461782d6e7323223e203c7264663a4465736372697074696f6e207264663a61626f75743d222220786d6c6e733a64633d22687474703a2f2f7075726c2e6f72672f64632f656c656d656e74732f312e312f2220786d6c6e733a70686f746f73686f703d22687474703a2f2f6e732e61646f62652e636f6d2f70686f746f73686f702f312e302f2220786d6c6e733a786d703d22687474703a2f2f6e732e61646f62652e636f6d2f7861702f312e302f2220786d6c6e733a786d704d4d3d22687474703a2f2f6e732e61646f62652e636f6d2f7861702f312e302f6d6d2f2220786d6c6e733a73744576743d22687474703a2f2f6e732e61646f62652e636f6d2f7861702f312e302f73547970652f5265736f757263654576656e7423222070686f746f73686f703a436f6c6f724d6f64653d2233222070686f746f73686f703a49434350726f66696c653d22735247422049454336313936362d322e312220786d703a4d65746164617461446174653d22323032322d31312d31395432323a35363a33312b30313a30302220786d703a4d6f64696679446174653d22323032322d31312d31395432323a35363a33312b30313a3030223e203c64633a7469746c653e203c7264663a416c743e203c7264663a6c6920786d6c3a6c616e673d22782d64656661756c74223e7965733c2f7264663a6c693e203c2f7264663a416c743e203c2f64633a7469746c653e203c786d704d4d3a486973746f72793e203c7264663a5365713e203c7264663a6c6920786d704d4d3a616374696f6e3d2270726f64756365642220786d704d4d3a736f6674776172654167656e743d22416666696e6974792044657369676e657220312e31302e352220786d704d4d3a7768656e3d22323032322d31312d31395432303a34343a32332b30313a3030222f3e203c7264663a6c692073744576743a616374696f6e3d2270726f6475636564222073744576743a736f6674776172654167656e743d22416666696e6974792050686f746f20312e31302e35222073744576743a7768656e3d22323032322d31312d31395432323a35363a33312b30313a3030222f3e203c2f7264663a5365713e203c2f786d704d4d3a486973746f72793e203c2f7264663a4465736372697074696f6e3e203c2f7264663a5244463e203c2f783a786d706d6574613e2020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020203c3f787061636b657420656e643d2277223f3effed005050686f746f73686f7020332e30003842494d04040000000000171c015a00031b25471c0200000200041c02050003796573003842494d0425000000000010acd1c50e9eee8829b1943af6ed4ce40dffe202644943435f50524f46494c45000101000002546c636d73043000006d6e74725247422058595a2007e6000b0013000f00240031616373704150504c0000000000000000000000000000000000000000000000000000f6d6000100000000d32d6c636d7300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b64657363000001080000003e63707274000001480000004c77747074000001940000001463686164000001a80000002c7258595a000001d4000000146258595a000001e8000000146758595a000001fc000000147254524300000210000000206754524300000210000000206254524300000210000000206368726d00000230000000246d6c756300000000000000010000000c656e5553000000220000001c0073005200470042002000490045004300360031003900360036002d0032002e003100006d6c756300000000000000010000000c656e5553000000300000001c004e006f00200063006f0070007900720069006700680074002c002000750073006500200066007200650065006c007958595a20000000000000f6d6000100000000d32d736633320000000000010c42000005defffff325000007930000fd90fffffba1fffffda2000003dc0000c06e58595a200000000000006fa0000038f50000039058595a20000000000000249f00000f840000b6c358595a2000000000000062970000b787000018d9706172610000000000030000000266660000f2a700000d59000013d000000a5b6368726d00000000000300000000a3d70000547b00004ccd0000999a0000266600000f5cffdb004300100b0c0e0c0a100e0d0e1211101318281a181616183123251d283a333d3c3933383740485c4e404457453738506d51575f626768673e4d71797064785c656763ffdb0043011112121815182f1a1a2f634238426363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363ffc00011080080008003012200021101031101ffc4001b00010001050100000000000000000000000006020304050701ffc40038100002020102030406060b000000000000000102030405110612213141517113142281a1b13242526191d1151623344472a2c1d2e1f0ffc4001a010100020301000000000000000000000000040501020306ffc40029110100020103020309010000000000000000010203041131125105214113141522324281a1b1e1ffda000c03010002110311003f00e80000001e01e835193c47838f64a1bd964a2f67cb1eff00798ef8af17bb1eef87e6739cb48f548ae973da378a4b7e08ecb8b29fa98b37e7248b32e2d9fd5c38fbe7fe8d673e3eee91a1d44fdbfc4a01139f15e4bfa18f547cdb6790e2bc95f4f1ea7e5ba31ef18fbb6f876a3b7ee12d06a34bd7a8cfb15528ba6e7d89bdd4bc99b73ad6d168de113263be3b74de3690006cd0000000002ddf2e5c7b24bb545bf8170b791fbbdbfc8fe42598e5cdfb7b400533d9000000002a84e55ce3383da517ba7e0ce8789935e563c2daa6a69a5bb5e273a36dc356db0d5ab85726a13df9d7735b1234f93a6db775778869fdae3ebdfcea9b000b179d000000000b3972e5c4ba5e15c9fc0bc63e72e6c0c84bbeb97c8c4f0cd79873b0014ef64000000001b0d0b2e387a9d739c778cbd8f2dfbcd799da363acad528ae4d28f3733ebdbb75d8de9bf546ce39e2b38add5c6d29e9e9e1e96cf240000000014ce3cd0945f7ad8a80104cbd0f3b1652fd8cac82ec943aefee35cd34da6b668e9846b8a74d5cab3aa8ecd74b36f8320e5d3c563aaabcd2f88cdef14c91cfaa3000222dc00cfab46d46e82943167cafb39b65f3331599e21a5f2529f54ecc02ba6d9d1742daded383dd3360f87f535fc3ff005afccc9c4e19cbb2c8fac38d55efd7aeecde315f7f2871beab045677b4259459e9b1ebb3edc54bf145c2984542118456ca2b64545abcac8000000000000516d70baa95762e68496cd78a2b0041357d2add36e7d1ca893f627fd9fde6b8e917535e4552aad829c24b66990dd6b46b34f9bb2bde78edf47df1fb995f9b074fcd5e17fa3d7464da9939feff00ac6d1acaebd5b1e56a5c9cdb75f17d9f127c73427da3667aee9b55adfb6972cbcd1d34b6e6ae3e2b8a77ae4fc338004c53000000000000000000000516d70b6b9576454a125b34fbcac01ceb3b1fd5736ea3ec4da5e5dc493841bf53c85dde917c8b7aaf0fe4e5ea53be99d6abb366dc9f55dc6ef4ec2af4fc48d15f5dbaca5e2fc4878b15ab9267d16faad5d3269eb589ded3b6eca001315000000000000000000000a1590763ad4e2e6bab8efd57b8f7d243d27273c79f6df977ebf8108d52dc9c4e2ccccec65cdeadc92b23e30718a7f33674645797c618f914cb9abb30f993fc40915b7554adedb2105e3292455194671528c94a2fb1a7b914d13069e20bb2f51d479ae5e95d75c1c9a515dbdde68bb835fe86e2a5a763ce5eab935f3c6b6f7e47d7fc58128000000000000000000000001a4c7d3aefd64d4726ea53c5bea8c22db4d4ba4535b76f7330747d072b4de22958a2e58718c9573725d13ea96dbee4a40119af0755d132f21e9d4432f12e973a839a8b83f7991a569b9b66ab3d57545085dcbc95d507bf22ff00be66f800000000000001ffd9037527a862a8e061ce54b290f08b2542358ec9d82b5909f87d37c425a383f7991a569b9b66ab3d57545085dcbc95d507bf22ff00be66f800000000000001ffd9037527a862a8e061ce54b290f08b254235000000006a9bf440bd18cc346b848dfd728e06107cfc7c58590457b174269b47a819677378d674e75717b38cb4c1d899c835393e77ef8ac2366906f23d7a1ca0c44587a1a53265b96bedce9336efec51ff4915b409013aaceb0063ca664f64f24b8aa1845f0ad97a608304e6bdd2dbf22402569ab6d864ed484f3328cba836c425d8bf1a3c5cd8fd2a4e73fe5cb6359576f0e08597d74cc34405281ff880335050a3aecd75509ea44f847da805e2e5f2b51f05af0d1832d8905e7abdd7a2227c412e241bf800fdb09c97bc11f6c412842e7102a793a894527be3a7ab503784dc33138fd2b2fc13ff48af9abd222c17c218f4d79f2b4a736622f67efad4e6e2794eeca6cae5983eb5eef36704a91578ec5f82c5dd9efb87e5e51b289c05eb6aefa9ca7b4e252839d299dcb24711aa196fd5b6a9af9147e137e1df9e788ccb8e8eede6a4814e59c957402cd6684eabf560277fe6195d635331a55005dd639de303c51d5ca468e6de7d5718f48a00dc4cce9476feda338a6b65bf712c368df0cdc71676b44c829a1054a3c7585dc3927bd9dca3660b6b4f078a85663f7ad5e0157412dd0d17aa43f5983441a66ed6900672f35bf14515698b98d173b9bdfc639c5cbcab9eec9ab30bb3f055536f'
def write_file(filename, data):
with open(filename, 'wb') as f:
f.write(data)
if __name__ == '__main__':
yes_data = binascii.unhexlify(yes)
write_file("yes.jpg", yes_data)
no_data = binascii.unhexlify(no)
write_file("no.jpg", no_data)
md5_yes = hashlib.md5(yes_data).hexdigest()
md5_no = hashlib.md5(no_data).hexdigest()
print("yes.jpg, md5 =", md5_yes)
print("no.jpg, md5 =", md5_no)
This question is related to Opening and checking a Pem file in SWI-Prolog
Once I have downloaded and opened the certificates how do I verify the signature chain?
I have:
:-use_module(library(http/http_client)).
url('https://s3.amazonaws.com/echo.api/echo-api-cert-4.pem').
url_data1(Url,Certs):-
http_open(Url,Stream,[]),
all_certs(Stream,Certs),
forall(member(C,Certs),my_validate(C)),
close(Stream).
all_certs(Stream,[C1|Certs]):-
catch(load_certificate(Stream,C1),_,fail),
all_certs(Stream,Certs),!.
all_certs(_Stream,[]).
my_validate(C):-
memberchk(to_be_signed(Signed),C),
memberchk(key(Key),C),
memberchk(signature(Signature),C),
memberchk(signature_algorithm(A),C),
algo_code(A,Code),
rsa_verify(Key,Signed,Signature,[type(Code)]).
algo_code('RSA-SHA256',sha256).
algo_code('RSA-SHA1',sha1).
This currently fails.
Preliminaries
Verifying digital signatures and entire certificate chains is extremely easy with Prolog.
However, you need to have a basic understanding of how certificates are signed. A certificate chain is a sequence of certificates C0, C1, ..., CN. I am using CN to denote the root certificate. Depending on the used convention, you may mutatis mutandis reverse the order of course.
Importantly, certificate Ck is signed using the private key corresponding to the public key of Ck+1.
Thus, one of the issues with your code is that you are mistakenly using the public key of C to verify the signature of C even though the certificate was signed with the private key corresponding to a different certificate.
A different issue stems from some confusion about what is being signed. We are signing the hash of the to-be-signed part of a certificate, not the data itself. Thus, we must verify the signature against that hash.
Concrete example
To make this answer self-contained, I post here the relevant data from your use case, i.e., the relevant attributes of the certificates that the file contains at the time of this writing.
Data
First certificate
From the first certificate in the chain, we need the signature and the to-be-signed portion, which are:
signature("7B86A6E7A86B192579380108B7EADA1C25E288AB46120117DC6A80635324C89713C70206EF3FE13CCA5EDFF43601972CB96658826ADCD68B0FB3AE7F5607D036D6AE8AF824CD96D7F1B4DB58E714343031F292B17E6EEF83872A0FD586CC0D1DA85A677E4AB4C6540E9132B5BC5644533E0388F830B1B6757B7DB88AB82846F08B3B6DCEC7F24319AB7EA56F86592DDDEC4522CAF331C8B81A4E543FBDBF4D661B534BAE546465DB88A525BC82A7B4127F0AFF4A55525927A66A09055743F109E30D90CA074D258166F0E472CB7CCDB0747ADE74F7040CFEEB9A78C3483864C5106D542556C874AF768005A6EC83ADEB2EE32F8E6F7182A362775C2BF40AFA20").
to_be_signed("30820466A00302010202103F25CAAEE5AA838FA91C051A75FC719D300D06092A864886F70D01010B0500307E310B3009060355040613025553311D301B060355040A131453796D616E74656320436F72706F726174696F6E311F301D060355040B131653796D616E746563205472757374204E6574776F726B312F302D0603550403132653796D616E74656320436C61737320332053656375726520536572766572204341202D204734301E170D3136313030373030303030305A170D3137313033303233353935395A306D310B30090603550406130255533113301106035504080C0A57617368696E67746F6E3110300E06035504070C0753656174746C6531193017060355040A0C10416D617A6F6E2E636F6D2C20496E632E311C301A06035504030C136563686F2D6170692E616D617A6F6E2E636F6D30820122300D06092A864886F70D01010105000382010F003082010A02820101009CAFB306BB910354E76E0406C44F9BE178934D9C83906C09EB4EBC006B1742682DF655610BC0934C2E30751E4D5E8B1BA15EBFEB7C28AD008DA38D7672C0558D4CB71F5FD512CFB92AFF80880394B8AA017C453CCC0BC709CEC698E29480D89D703034312A71DD94CC48619B91F68B8A44739DEEA7159EA334E9E4A93B460FA4AB0886202CD02B49C6283F321C5C4CA91C5AE8827CEB47811ED1871E7C66724BCD58A9EBFF9658B4D5D02046FA6702DCBAF2B6139B190D8735121BA2086C51C8C5724A0044C090688A25C819A5F1B6D4E9390E4DF21AB11263F203E4E9F1BCCC625D29D7C21B7C243E9B775E6E8B4B4F0DAF390748E964B968A9065EDBAA11A30203010001A382020730820203301E0603551D110417301582136563686F2D6170692E616D617A6F6E2E636F6D30090603551D1304023000300E0603551D0F0101FF0404030205A0301D0603551D250416301406082B0601050507030106082B0601050507030230610603551D20045A30583056060667810C010202304C302306082B06010505070201161768747470733A2F2F642E73796D63622E636F6D2F637073302506082B0601050507020230190C1768747470733A2F2F642E73796D63622E636F6D2F727061301F0603551D230418301680145F60CF619055DF8443148A602AB2F57AF44318EF302B0603551D1F042430223020A01EA01C861A687474703A2F2F73732E73796D63622E636F6D2F73732E63726C305706082B06010505070101044B3049301F06082B060105050730018613687474703A2F2F73732E73796D63642E636F6D302606082B06010505073002861A687474703A2F2F73732E73796D63622E636F6D2F73732E637274300F06032B654D0408300602010102010130818B060A2B06010401D679020402047D047B0079007700A7CE4A4E6207E0ADDEE5FDAA4B1F86768767B5D002A55D47310E7E670A95EAB2000001579FAA404A0000040300483046022100CA6B7C069C140B774E8D64ED95D4A59E92349E04AA3C71B304F32C74BC857F81022100FA152CF8558BA0A87B515AB7522D1BE1725740E128042309DD274FEEA5EB3B62").
Second certificate
From the second certificate, we only need the public key to verify the signature that was issued for the previous certificate:
key(public_key(rsa("B2D805CA1C742DB5175639C54A520996E84BD80CF1689F9A422862C3A530537E5511825B037A0D2FE17904C9B496771981019459F9BCF77A9927822DB783DD5A277FB2037A9C5325E9481F464FC89D29F8BE7956F6F7FDD93A68DA8B4B82334112C3C83CCCD6967A84211A22040327178B1C6861930F0E5180331DB4B5CEEB7ED062ACEEB37B0174EF6935EBCAD53DA9EE9798CA8DAA440E25994A1596A4CE6D02541F2A6A26E2063A6348ACB44CD1759350FF132FD6DAE1C618F59FC9255DF3003ADE264DB42909CD0F3D236F164A8116FBF28310C3B8D6D855323DF1BD0FBD8C52954A16977A522163752F16F9C466BEF5B509D8FF2700CD447C6F4B3FB0F7", "010001", -, -, -, -, -, -))).
Verification
Computing the hash
As I said, a hash is what was actually signed. Critically, I don't mean the hash of the whole certificate, but the hash of the to-be-signed portion. This difference is important, because the hash of the whole certificate also comprises the signature, and that is of course not yet available when the certificate is being signed.
In SWI-Prolog, we can obtain the hash of the to-be-signed portion using library(crypto):
?- to_be_signed(TBS),
hex_bytes(TBS, Bytes),
crypto_data_hash(Bytes, Hash, [algorithm(sha256), encoding(octet)]).
TBS = "3082...EB3B62",
Bytes = [48, 130, 4, 102, 160, 3, 2, 1, 2|...],
Hash = '651bdcdd90251f71a47a5d1bbc6f28486c94d2dc3739dcd58ecb09b3f224ee05'.
I am using sha256 because the first certificate indicates (RSA and) SHA256 in its signature_algorithm/1 field.
Verifying the signature using CLP(FD) constraints
One of the easiest ways to verify an RSA signature is to use CLP(FD) constraints. We only need to compute SigExp mod p. We plug in our concrete numbers, using (#=)/2 to evaluate the arithmetic expression over integers:
?- X #= 0x7B86A6E7A86B192579380108B7EADA1C25E288AB46120117DC6A80635324C89713C70206EF3FE13CCA5EDFF43601972CB96658826ADCD68B0FB3AE7F5607D036D6AE8AF824CD96D7F1B4DB58E714343031F292B17E6EEF83872A0FD586CC0D1DA85A677E4AB4C6540E9132B5BC5644533E0388F830B1B6757B7DB88AB82846F08B3B6DCEC7F24319AB7EA56F86592DDDEC4522CAF331C8B81A4E543FBDBF4D661B534BAE546465DB88A525BC82A7B4127F0AFF4A55525927A66A09055743F109E30D90CA074D258166F0E472CB7CCDB0747ADE74F7040CFEEB9A78C3483864C5106D542556C874AF768005A6EC83ADEB2EE32F8E6F7182A362775C2BF40AFA20^0x010001
mod 0xB2D805CA1C742DB5175639C54A520996E84BD80CF1689F9A422862C3A530537E5511825B037A0D2FE17904C9B496771981019459F9BCF77A9927822DB783DD5A277FB2037A9C5325E9481F464FC89D29F8BE7956F6F7FDD93A68DA8B4B82334112C3C83CCCD6967A84211A22040327178B1C6861930F0E5180331DB4B5CEEB7ED062ACEEB37B0174EF6935EBCAD53DA9EE9798CA8DAA440E25994A1596A4CE6D02541F2A6A26E2063A6348ACB44CD1759350FF132FD6DAE1C618F59FC9255DF3003ADE264DB42909CD0F3D236F164A8116FBF28310C3B8D6D855323DF1BD0FBD8C52954A16977A522163752F16F9C466BEF5B509D8FF2700CD447C6F4B3FB0F7.
It yields:
X = 986236757547332986472011617696226561292849812918563355472727826767720188564083584387121625107510786855734801053524719833194566624465665316622563244215340671405971599343902468620306327831715457360719532421388780770165778156818229863337344187575566725786793391480600129482653072861971002459947277805295727097226389568776499707662505334062639449916265137796823793276300221537201727072401742985542559596685092673521228140822200236743113743661549252453726123450722876929538747702356573783116197523966334991563351853851212597377279504828784716104866621888265058037501385433453379649364782998949981722124880992983641605.
Excursion: On efficiency and use of CLP(FD).
You may now say: "Well, I don't really need (#=)/2, I can always use (is)/2 which I learned decades ago." But, if you are using (is)/2 in such examples, you easily end up with code that is thousands of times less efficient. As a simple benchmark, consider the predicate:
signature_pow(Sig, Exp, P, Pow) :-
Pow #= Sig^Exp mod P.
Now we have, for the query:
?- time(signature_pow(0x7B86A6E7A86B192579380108B7EADA1C25E288AB46120117DC6A80635324C89713C70206EF3FE13CCA5EDFF43601972CB96658826ADCD68B0FB3AE7F5607D036D6AE8AF824CD96D7F1B4DB58E714343031F292B17E6EEF83872A0FD586CC0D1DA85A677E4AB4C6540E9132B5BC5644533E0388F830B1B6757B7DB88AB82846F08B3B6DCEC7F24319AB7EA56F86592DDDEC4522CAF331C8B81A4E543FBDBF4D661B534BAE546465DB88A525BC82A7B4127F0AFF4A55525927A66A09055743F109E30D90CA074D258166F0E472CB7CCDB0747ADE74F7040CFEEB9A78C3483864C5106D542556C874AF768005A6EC83ADEB2EE32F8E6F7182A362775C2BF40AFA20, 0x010001, 0xB2D805CA1C742DB5175639C54A520996E84BD80CF1689F9A422862C3A530537E5511825B037A0D2FE17904C9B496771981019459F9BCF77A9927822DB783DD5A277FB2037A9C5325E9481F464FC89D29F8BE7956F6F7FDD93A68DA8B4B82334112C3C83CCCD6967A84211A22040327178B1C6861930F0E5180331DB4B5CEEB7ED062ACEEB37B0174EF6935EBCAD53DA9EE9798CA8DAA440E25994A1596A4CE6D02541F2A6A26E2063A6348ACB44CD1759350FF132FD6DAE1C618F59FC9255DF3003ADE264DB42909CD0F3D236F164A8116FBF28310C3B8D6D855323DF1BD0FBD8C52954A16977A522163752F16F9C466BEF5B509D8FF2700CD447C6F4B3FB0F7, Pow)).
the timing:
% 16 inferences, 0.000 CPU in 0.000 seconds (99% CPU, 130624 Lips)
In contrast, if we regress in Prolog language development and replace (#=)/2 by (is)/2, we get:
% 3 inferences, 1.847 CPU in 1.852 seconds (100% CPU, 2 Lips)
Reason: In SWI-Prolog, certain goals involving (#=)/2 automatically use specialized arithmetic predicates. You do not need to learn these predicates to use them. CLP(FD) does it for you.
Recommendation: Use CLP(FD) constraints for reasoning over integers in Prolog. They typically make your predicates more general, and sometimes vastly more efficient. clpfd
Now, what about X? To see what it is, consider its hexadecimal encoding:
?- format("~16r", [$X]).
1fffffff...fff003031300d060960864801650304020105000420651bdcdd90251f71a47a5d1bbc6f28486c94d2dc3739dcd58ecb09b3f224ee05
This sounds familiar: At the end, you see that the hash of the to-be-signed portion of the certificate appears. This means that the signature checks out!
Verifying the signature with rsa_verify/4
Alternatively, we can use rsa_verify/4 from library(crypto) to verify the signature.
Here is the full query:
?- to_be_signed(TBS),
hex_bytes(TBS, Bytes),
crypto_data_hash(Bytes, Hash, [algorithm(sha256), encoding(octet)]),
signature(Sig),
key(Key),
rsa_verify(Key, Hash, Sig, [type(sha256)]).
Since this succeeds, we know that the private key corresponding to Key was used to produce the signature.
Closing remarks
I have one important remark: Normally, this is all of course completely unnecessary!
The SWI-Prolog SSL infrastructure automatically verifies the certificate chain and thus all signatures every single time you use http_open/3 and related predicates to make a connection via TLS. But it is interesting to make these calculations yourself. Sometimes it is even necessary, if, as in this example, you are reasoning over certificates you have stored somewhere.
One small additional remark: Please use setup_call_cleanup/3 in your code. Otherwise, you risk leaking file descriptors if anything goes wrong before close/1, which is in fact even the case in your example.
Facebook app secret is a string of 32 characters (0-9, a-f) and thus it represents a 128 bits byte array. Facebook uses this as the key to generate signed request using HMAC-SHA256. Is this a correct usage? I thought HMAC-SHA256 should use 256 bits keys.
HMAC takes the HASH(key) and uses it as the key if the length of the key is greater than the internal block size of the hash. Thus, a key larger than the internal block size of the hash provides no better security than one of equal size. Shorter keys are zero padded to be equal to the internal block size of the hash as per the HMAC specification.
It's impossible to use a 128-bit key with HMAC-SHA-256. If you mean 128 bits padded out to 512 bits with zeroes, then it's probably alright for short-term authentication. I'd recommend at least 256 bits and ideally you would want to use something equal to the internal block size of the underlying hash.
The page says that the 256bit signature is derived from a payload (what facebook is signing) + your 128 bit salt.
So yes, it sounds like correct usage.
The secret 16 bytes (32 characters) isn't actually a key in the sense that it's used to encrypt and decrypt something. Rather, it's a bit of data (a salt) that is used to alter the result of the digital signature, by changing the input ever-so-slightly, so that only someone who knew the exact secret and the exact payload could have created the signature.
I use RSACryptoServiceProvider to encrypt some small blocks of data. For the solution I'm working on, it's important that if the same piece of source data is encrypted twice with the same public key, the result (the encrypted block of data) is not the same.
I have checked this with an example and it worked like I hoped. My question is now, if this behaviour is by design and guaranteed or if I have to add some random part to the source data for guaranteeing that data blocks with the same data can not be matched anymore after encryption.
Here is the example:
byte[] data=new byte[]{1,7,8,3,4,5};
RSACryptoServiceProvider encrypter = cert.PublicKey.Key as RSACryptoServiceProvider;
byte[] encryptedData = encrypter.Encrypt(data,true);
// encryptedData has always other values in, although the source data is always
// 1,7,8,3,4,5 and the certificate is always the same (loaded from disk)
The concrete question is for .net but maybe the answer can be given in general for all RSA-implementations if it is by design?
The text-book RSA encryption algorithm is deterministic:
ciphertext = plaintext ^ encryption-exponent mod modulus
(Here ^ is integer exponentiation, mod the remainder operation.)
But as you remarked, this does not provide a good security guarantee, as an attacker which can guess the plaintext can simply verify this guess by encrypting it himself and comparing the results.
For this reason, the official RSA specifications (and also all implementations used in practice) include some (partly random) padding, so we don't actually encrypt plaintext, but pad(plaintext):
ciphertext = pad(plaintext) ^ encryption-exponent mod modulus
Decryption:
plaintext = unpad( ciphertext ^ decryption-exponent mod modulus )
Only with this padding RSA is actually a secure encryption scheme.
A similar padding is also used for RSA signatures, to avoid easy forging of signatures.
I'm trying to encrypt some date using a public key derived form the exchange key pair made with the CALG_RSA_KEYX key type. I determined the block size was 512 bits using cryptgetkeyparam KP_BLOCKLEN. It seems the maximum number of bytes I can feed cryptencrypt in 53 (424 bits) for which I get an encrypted length of 64 back. How can I determine how many bytes I can feed into cryptencrypt? If I feed in more than 53 bytes, the call fails.
RSA using the usual PKCS#1 v.1.5 mode can encrypt a message that is at most k-11 bytes, where k is the length of the modulus in bytes. So a 512 bit key can encrypt up to 53 bytes and a 1024 bit key can encrypt up to 117 bytes.
RSA using OAEP can encrypt a message up to k-2*hLen-2, where k is the modulus byte-length and hLen is the length of the output of the underlying hash-function. So using SHA-1, a 512 bit key can encrypt up to 22 bytes and a 1024 bit key can encrypt up to 86 bytes.
You should not normally use a RSA key to encrypt your message directly. Instead you should generate a random symmetric key (f.x. an AES key), encrypt your message with the symmetric key, encrypt the key with the RSA key and transmit both encryptions to the recipient. This is usually called hybrid encryption.
EDIT: Although this response is marked as accepted by the OP, please see Rasmus Faber response instead, as this is a much better response. Posted 24 hours later, Rasmus's response corrects factual errors,in particular a mis-characterization of OAEP as a block cipher; OAEP is in fact a scheme used atop PKCS-1's Encoding Primitive for the purpose of key-encryption. OAEP is more secure and puts an even bigger limit on the maximum message length, this limit is also bound to a hash algorithm and its key length.
Another shortcoming of the following reply is its failure to stress that CALG_RSA_KEYX should be used exclusively for the key exchange, after which transmission of messages of any length can take place with whatever symmetric key encryption algorithm desired. The OP was aware of this, he was merely trying to "play" with the PK, and I did cover that much, albeit deep in the the long remarks thread.
Fore the time being, I'm leaving this response here, for the record, and also as Mike D may want to refer to it, but do remark-me-in, if you think that it would be better to remove it altogether; I don't mind doing so for sake of clarity!
-mjv- Sept 29, 2009
Original reply:
Have you check the error code from GetLastError(), following cryptencrypt()'s false return?
I suspect it might be NTE_BAD_LEN, unless there's be some other issue.
Maybe you can post the code that surrounds your calling criptencryt().
Bingo, upon seeing the CryptEncrypt() call.
You do not seem to be using the RSAES w/ OAEP scheme, since you do not have the CRYPT_OAEP flag on. This OAEP scheme is a block cipher based upon RSAES. This latter encryption algorihtm, however, can only encrypt messages slightly less than its key size (expressed in bytes). This is due to the minimum padding size defined in PKCS#1; such padding helps protect the algorithm from some key attacks, I think the ones based on known cleartext).
Therefore you have three options:
use the CRYPT_OAEP in the Flag parameter to CryptEncrypt()
extend the key size to say 1024 (if you have control over it, beware that longer keys will increase the time to encode/decode...)
Limit yourself to clear-text messages shorter than 54 bytes.
For documentation purposes, I'd like to make note of a few online resources.
- The [RSA Labs][1] web site which is very useful in all things crypto.
- Wikipedia articles on the subject are also quite informative, easier to read
and yet quite factual (I think).
When in doubt, however, do consult a real crypto specialist, not someone like me :-)