I want to use an asymmetric cryptography algorithm, but I need it have short Key Size(not like RSA which is at least 384).
I need it to be about around 20.
Is it possible?
That's a .NET restriction on the key size; RSA can be used with any key size. It just doesn't make sense to do so.
Think about it, with a 20-bit key you can brute force the it in 2^20 attempts and that's just too easy with today's computers.
There are several ways to have a short key size.
1. With RSA
A RSA public key consists in a big number n (the "modulus") and a (usually small) number e (the public exponent). e can be as small as 3, and in a closed setup (where you control key generation) you can force the use of a conventional e, the same for everybody. A typical size for n is 1024 bits (i.e. 128 bytes).
n is the product of two prime numbers (n = p*q). Knowledge of p and q is sufficient to rebuild the private key (nominally a value d which is a multiplicative inverse of e modulo p-1 and q-1). Assuming that n is known, knowledge of p alone is sufficient (if you know n and p, you can compute q with a simple division). For proper security, p and q should have similar sizes, so even by taking the smaller of the two, you still need to store about 512 bits or so -- that's 64 bytes).
It has also been suggested to select a small d (the "private exponent"). But this makes e essentially random, hence large; you can no longer use a conventional small value for e. This basically doubles the public key size. Also, forcing a small d can make the key weak (it has been shown to be the case when the size of d is no more than 29% of the size of n, but that does not prove in any way that a d of 30% the size of n is safe). This is generally considered to be a bad idea.
2. With DSA / Diffie-Hellman
DSA is a digital signature algorithm. Diffie-Hellman is a key exchange algorithm. Both are "asymmetric cryptographic algorithms" and you would use one or the other, or both, depending on your needs. In both cases, there is a public mathematical group (numbers modulo a big prime number p for the basic DSA and DH; elliptic curve variants use an elliptic curve as group); the public key is a group element, and the private key is the discrete logarithm of that element relatively to a conventional generator. In other words, a prime p and a number g modulo p are given (they can be shared by all key holders, even); a private key is a number x corresponding to the public key y = gx mod p. The private key is chosen modulo a small prime q. q is known and must be large enough so as to defeat the generic discrete logarithm algorithms; in practice, we want a 160-bit or more q.
This means that a private key fits in about 20 bytes. That's not 20 decimal digits, but closer.
3. With ANY cryptographic algorithm
When you generate a key pair, you do so with:
a deterministic procedure;
a source of random bits.
For instance, with RSA, you generate p and q by creating random odd numbers of the right size and looping until a prime number is found. For a given random source, the whole process is deterministic: given the same random bits, this will find the same primes p and q.
Hence you can develop a PRNG seeded by a secret key K and use it as random source for the key generation process. Whenever you need the private key, you run the key generation process again, using K as input. And voilĂ ! Your private key, the one you need to store, is now K.
With RSA, this makes private key usage quite expensive (RSA key generation is not easy). However, with DSA / Diffie-Hellman, this would be very inexpensive: the private key is only a random number modulo q (the group order) which can be generated with much less cost than using the private key for a digital signature or an asymmetric key exchange.
This leads to the following procedure:
The "private key", as stored, is K.
The group parameters for DSA / Diffie-Hellman are hardcoded in the application; everybody uses the same group and that is not a problem. The group order is q, a known prime of at least 160 bits. If you use an elliptic curve variant, then q is a property of the curve, hence a given.
When you need to sign or to perform a key exchange (key exchange is used to emulate asymmetric encryption), you compute SHA-512(K), which yields a 512-bit sequence. You take the first half (256 bits), interpret it as a number (with big-endian or little-endian convention, as you wish, provided that you always use the same convention), and reduce it modulo q to get the private DSA key. Similarly, you use the second half of the SHA-512 output to get the private DH key.
The key generation is very slightly biased but this does not imply much security trouble. Note that if you need a DSA key and a DH key, then you can use the same group but you should not use the same private key (hence the use of both halves of the SHA-512 output).
How big should be K ? With a hash function such as SHA-512, K can be any arbitrary sequence of bits. However, K should be wide enough to defeat exhaustive search. A 1024-bit RSA key, or a 1024-bit DSA modulus (the p modulus for DSA), provide a security level which is very roughly equivalent to an 80-bit symmetric key. Similarly, a 160-bit group order for DSA/DH provides the same level. 80 bits are not that much; you cannot go lower than that if you want to be taken seriously. This means that K should be chosen among a space of at least 280 possible keys; in other words, if K is selected as uniformly random bytes, then it must be at least 10 bytes long. With decimal digits, you need at least 24 digits. Anything below that is intrinsically weak, and that's unavoidable.
Standard warning: if anything of the above is not obvious or crystal clear to you, then do not even think about implementing it. Implementation of cryptographic algorithm is tricky, especially since the deadliest errors cannot be tested (it is not because the program runs and appears to work properly that it does not contain security weaknesses).
You may want to consider using Elliptic Curve Cryptography, if you can find a standard implementation of it. It provides the same level of protection against brute force as RSA, with substantially shorter key lengths.
The standard disclaimer about cooking up your own cryptosystems applies here, of course.
Related
I'm implementing a short RSA program and have this code:
private string Encrypt(string data)
{
BigInteger dataAsBigInteger = new BigInteger(Encoding.UTF8.GetBytes(data));
BigInteger remainder = BigInteger.ModPow(dataAsBigInteger, exponentE, CalculatePublicKey());
return Convert.ToBase64String(remainder.ToByteArray());
}
private string Decrypt(string data)
{
BigInteger dataAsBigInteger = new BigInteger(Convert.FromBase64String(data));
BigInteger remainder = BigInteger.ModPow(dataAsBigInteger, CalculatePrivateKey(), CalculatePublicKey());
return Encoding.UTF8.GetString(remainder.ToByteArray());
}
Unfortunately, I seem to be getting weird ASCII values for the result. I tried with just using numbers instead of text and Decrypt(Encrypt(number)) == number so I know the algorithm is fine so I think it is messing up because of converting to and from byte arrays and performing operations on them.
If this didn't work I was thinking of a better idea for a formula of converting letters to numbers. I can't do A = 1, B = 2, etc. because 11 would be ambiguous with K (11th letter). Maybe if each letter's position (A = 1, B = 2, etc.) was first multiplied by 10 and then you would know the next letter began at a non-zero value?
Is something like this advisable or can the byte arrays be salvaged?
In principle your scheme should work, as long as the resulting BigInteger is not negative or larger than the modulus.
If a cryptographically secure RSA implementation such as OAEP is used then you also need to subtract the overhead of the padding. Usually though you should only encrypt a symmetric key and use hybrid cryptography to allow for almost arbitrary message sizes.
The thing you are trying to do does not make sense. RSA can only encrypt fixed-length messages, integers of the same order-of-magnitude as the public modulus n. (Specifically, if the plaintext m, taken as a number, is small enough that me < n, then the encryption is trivially reversible, and if it is larger than n, it can't be encrypted at all.)
Moreover, you appear to be attempting to implement "textbook RSA", which is insecure. You need to redesign your application so that, instead, it uses RSA as part of a key encapsulation scheme, which securely delivers a symmetric (e.g. AES) key which is used, in an authenticated operation mode, to encrypt the actual message.
This correction to your design will also render your encoding problem moot, since the message proper is now being encrypted using a symmetric cipher that operates on bit streams rather than numbers.
I would be very surprised if C# does not have libraries that do this for you.
i was playing around with RSA Key creation and start to measure the time it takes to create RSA key with a specific bit strength.
My key question was, how long does it take to create a 16384 bit RSA key (around 140s).
I expected a steady logarithmic increase, but I got this: (x: bit; y: seconds)
All keys are created with:
csp = new RSACryptoServiceProvider(keyStrength); (c#, net 4.0)
So why did I get this sawtooth wave?
Well, clearly the graph implies they are not producing primes by doing the classical primality test of randomly generated numbers for each prime to produce the RSA key.
So, the only thing left to assume is that they used some sort of primes families generator which works in pre-segmented ranges.
You can read more here:
https://crypto.stackexchange.com/questions/71/how-can-i-generate-large-prime-numbers-for-rsa
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'm looking for a PRNG (pseudo randomness) that you initially seed with an arbitrary array of bytes.
Heard of any?
Hashing your arbitrary length seed (instead of using XOR as paxdiablo suggested) will ensure that collisions are extremely unlikely, i.e. equal to the probability of a hash collision, with something such as SHA1/2 this is a practical impossibility.
You can then use your hashed seed as the input to a decent PRNG such as my favourite, the Mersenne Twister.
UPDATE
The Mersenne Twister implementation available here already seems to accept an arbitrary length key: http://code.msdn.microsoft.com/MersenneTwister/Release/ProjectReleases.aspx?ReleaseId=529
UPDATE 2
For an analysis of just how unlikely a SHA2 collision is see how hard someone would have to work to find one, quoting http://en.wikipedia.org/wiki/SHA_hash_functions#SHA-2 :
There are two meet-in-the-middle preimage attacks against SHA-2 with a reduced number of rounds. The first one attacks 41-round SHA-256 out of 64 rounds with time complexity of 2^253.5 and space complexity of 2^16, and 46-round SHA-512 out of 80 rounds with time 2^511.5 and space 2^3. The second one attacks 42-round SHA-256 with time complexity of 2^251.7 and space complexity of 2^12, and 42-round SHA-512 with time 2^502 and space 2^22.
Why don't you just XOR your arbitrary sequence into a type of the right length (padding it with part of itself if necessary)? For example, if you want the seed "paxdiablo" and your PRNG has a four-byte seed:
paxd 0x70617864
iabl 0x6961626c
opax 0x6f706178
----------
0x76707b70 or 0x707b7076 (Intel-endian).
I know that seed looks artificial (and it is since the key is chosen from alpha characters). If you really wanted to make it disparate where the phrase is likely to come from a similar range, XOR it again with a differentiator like 0xdeadbeef or 0xa55a1248:
paxd 0x70617864 0x70617864
iabl 0x6961626c 0x6961626c
opax 0x6f706178 0x6f706178
0xdeadbeef 0xa55a1248
---------- ----------
0xa8ddc59f 0xd32a6938
I prefer the second one since it will more readily move similar bytes into disparate ranges (the upper bits of the bytes in the differentiator are disparate).
I have a little problem where need to do a hash of a number of about 10 digits into a number of 6 digits. The hash needs to be deterministic.
It's more important that the hash is not resource intensive.
For example, say that I have some number, x, like 123456789
I want to write an hash function that gives me a number, y, back like 987654.
I'd then like to have a function that takes the x and y as parameters, re-applies the hash on x, and checks that the result is y.
It should be difficult to compute possible input values given the hash.
My first idea of multiplying pairs of digits led to a lot of duplicate hashed values.
I have the feeling that this sort of problem has some kind of elegant solution, but I just can't think of it myself.
Can anyone help me out here? Thanks in advance :)
What you need is called "hashing".
Try CRC16.
Your problem as stated is not solvable.
You say that you want the system to be "somewhat hard to break", by which I assume you mean that it is "somewhat hard" for an attacker to take a known digest and produce from it a possible input which hashes to the given digest. Since there are only 4 billion possible inputs and only 65536 possible hashes in the system you propose, it is utterly trivial to find a message that corresponds to a given hash, no matter what the hash algorithm is. On average, the attacker will have about 65000 possible messages to choose from, and can therefore cherry-pick the message that best serves his nefarious scheme.
I would expect a "somewhat hard" problem in the hash-breaking space to require, dedicating, say, a few million dollars worth of supercomputer time to break. Your proposal can be broken by inexperienced high school students writing Javascript programs that take a couple minutes to write and maybe a minute to run, tops; this is not even vaguely close to "somewhat hard".
Why are you choosing such tiny limits on your algorithm, limits which will by their very nature make it trivial to break the hashing? And for that matter, what's the value in hashing such a tiny amount of data as a 32 bit integer?
(( X>>16) ^ (X)) & 0xFFFF
.......
What you want to do is to try to distribute the hash values as evenly as possible over the range. Some of the built in hashing methods are fairly good at this, so you could perhaps try something like getting the hash code of the string representation, and simply throw away half of the bits:
ushort code = (ushort)value.ToString().GetHashCode();
However, it also depends on what you are going to use the hash code for. The built in hash codes are not intended to be stored permanently. The algorithms for calculating the hash codes can change with any new version of the framework, so if you store the hash codes in the database they may become useless in the future. In that case you would instead have to create the hashing algorithm yourself from scratch, or use some hashing algorithm that was designed for permanent storage.
One simple algorithm that is used for hash codes for some values in the framework is to use exclusive or to make all bits in the value matter when the hash code is smaller than the data:
byte[] b = BitConverter.GetBytes(value);
ushort code = (ushort)(BitConverter.ToUInt16(b, 0) ^ BitConverter.ToUInt16(b, 2));
or the more efficient but less obvious way to do the same:
ushort code = (ushort)((value >> 16) ^ value);
This of course has no obfuscating properties for small values, so you might want to throw in some "random" bits to make the hash code significantly different from the value:
ushort code = (ushort)(0x56D4 ^ (value >> 16) ^ value);
How about just discarding the lower 16 bits or last 4 digits?
1234567890 --> 123456
Easily done by just doing an integer division by 10000.