RSA creation time, why drop after 16384bit? - c#

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

Related

How to generate unusual but mathematically valid RSA keys?

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

How is a random number generated at runtime?

Since computers cannot pick random numbers(can they?) how is this random number actually generated. For example in C# we say,
Random.Next()
What happens inside?
You may checkout this article. According to the documentation the specific implementation used in .NET is based on Donald E. Knuth's subtractive random number generator algorithm. For more information, see D. E. Knuth. "The Art of Computer Programming, volume 2: Seminumerical Algorithms". Addison-Wesley, Reading, MA, second edition, 1981.
Since computers cannot pick random numbers (can they?)
As others have noted, "Random" is actually pseudo-random. To answer your parenthetical question: yes, computers can pick truly random numbers. Doing so is much more expensive than the simple integer arithmetic of a pseudo-random number generator, and usually not required. However there are applications where you must have non-predictable true randomness: cryptography and online poker immediately come to mind. If either use a predictable source of pseudo-randomness then attackers can decrypt/forge messages much more easily, and cheaters can figure out who has what in their hands.
The .NET crypto classes have methods that give random numbers suitable for cryptography or games where money is on the line. As for how they work: the literature on crypto-strength randomness is extensive; consult any good university undergrad textbook on cryptography for details.
Specialty hardware also exists to get random bits. If you need random numbers that are drawn from atmospheric noise, see www.random.org.
Knuth covers the topic of randomness very well.
We don't really understand random well. How can something predictable be random? And yet pseudo-random sequences can appear to be perfectly random by statistical tests.
There are three categories of Random generators, amplifying on the comment above.
First, you have pseudo random number generators where if you know the current random number, it's easy to compute the next one. This makes it easy to reverse engineer other numbers if you find out a few.
Then, there are cryptographic algorithms that make this much harder. I believe they still are pseudo random sequences (contrary to what the comment above implies), but with the very important property that knowing a few numbers in the sequence does NOT make it obvious how to compute the rest. The way it works is that crypto routines tend to hash up the number, so that if one bit changes, every bit is equally likely to change as a result.
Consider a simple modulo generator (similar to some implementations in C rand() )
int rand() {
return seed = seed * m + a;
}
if m=0 and a=0, this is a lousy generator with period 1: 0, 0, 0, 0, ....
if m=1 and a=1, it's also not very random looking: 0, 1, 2, 3, 4, 5, 6, ...
But if you pick m and a to be prime numbers around 2^16, this will jump around nicely looking very random if you are casually inspecting. But because both numbers are odd, you would see that the low bit would toggle, ie the number is alternately odd and even. Not a great random number generator. And since there are only 2^32 values in a 32 bit number, by definition after 2^32 iterations at most, you will repeat the sequence again, making it obvious that the generator is NOT random.
If you think of the middle bits as nice and scrambled, while the lower ones aren't as random, then you can construct a better random number generator out of a few of these, with the various bits XORed together so that all the bits are covered well. Something like:
(rand1() >> 8) ^ rand2() ^ (rand3() > 5) ...
Still, every number is flipping in synch, which makes this predictable. And if you get two sequential values they are correlated, so that if you plot them you will get lines on your screen. Now imagine you have rules combining the generators, so that sequential values are not the next ones.
For example
v1 = rand1() >> 8 ^ rand2() ...
v2 = rand2() >> 8 ^ rand5() ..
and imagine that the seeds don't always advance. Now you're starting to make something that's much harder to predict based on reverse engineering, and the sequence is longer.
For example, if you compute rand1() every time, but only advance the seed in rand2() every 3rd time, a generator combining them might not repeat for far longer than the period of either one.
Now imagine that you pump your (fairly predictable) modulo-type random number generator through DES or some other encryption algorithm. That will scramble up the bits.
Obviously, there are better algorithms, but this gives you an idea. Numerical Recipes has a lot of algorithms implemented in code and explained. One very good trick: generate not one but a block of random values in a table. Then use an independent random number generator to pick one of the generated numbers, generate a new one and replace it. This breaks up any correlation between adjacent pairs of numbers.
The third category is actual hardware-based random number generators, for example based on atmospheric noise
http://www.random.org/randomness/
This is, according to current science, truly random. Perhaps someday we will discover that it obeys some underlying rule, but currently, we cannot predict these values, and they are "truly" random as far as we are concerned.
The boost library has excellent C++ implementations of Fibonacci generators, the reigning kings of pseudo-random sequences if you want to see some source code.
I'll just add an answer to the first part of the question (the "can they?" part).h
Computers can generate (well, generate may not be an entirely accurate word) random numbers (as in, not pseudo-random). Specifically, by using environmental randomness which is gotten through specialized hardware devices (that generates randomness based on noise, for e.g.) or by using environmental inputs (e.g. hard disk timings, user input event timings).
However, that has no bearing on the second question (which was how Random.Next() works).
The Random class is a pseudo-random number generator.
It is basically an extremely long but deterministic repeating sequence. The "randomness" comes from starting at different positions. Specifying where to start is done by choosing a seed for the random number generator and can for example be done by using the system time or by getting a random seed from another random source. The default Random constructor uses the system time as a seed.
The actual algorithm used to generate the sequence of numbers is documented in MSDN:
The current implementation of the Random class is based on Donald E. Knuth's subtractive random number generator algorithm. For more information, see D. E. Knuth. "The Art of Computer Programming, volume 2: Seminumerical Algorithms". Addison-Wesley, Reading, MA, second edition, 1981.
Computers use pseudorandom number generators. Essentially, they work by start with a seed number and iterating it through an algorithm each time a new pseudorandom number is required.
The process is of course entirely deterministic, so a given seed will generate exactly the same sequence of numbers every time it is used, but the numbers generated form a statistically uniform distribution (approximately), and this is fine, since in most scenarios all you need is stochastic randomness.
The usual practice is to use the current system time as a seed, though if more security is required, "entropy" may be gathered from a physical source such as disk latency in order to generate a seed that is more difficult to predict. In this case, you'd also want to use a cryptographically strong random number generator such as this.
I don't know much details but what I know is that a seed is used in order to generate the random numbers it is then based on some algorithm that uses that seed that a new number is obtained.
If you get random numbers based on the same seed they will be the same often.

Custom Asymmetric Cryptography Algorithm

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.

RSA private key encryption

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.

Looking for PRNG that you can seed with any number bytes

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).

Categories