RSA Public key Cryptography This is in many ways the jewel in the crown of number theoretic cryptography. The idea here (envisaged first by Diffie and Hellman) was for an encryption system with a public encryption key and a private decryption key. In fact the idea is not outlandish at all- it is the precise analogue of a padlock. Anyone can close a padlock - only the possessor of the key can open it. If you want to send me a secret, I send you an empty box and my open padlock. You pop the secret in the box, put on the padlock and close it, and send it back to me. I open it with my padlock key. As a manual way of transmitting secrets, this is perfectly viable. A padlock is a kind of one-way function - if you don’t have the key. Anyone can squeeze it shut, but its virtually impossible to open. However possession of the key acts as a kind of trap-door that springs it open instantly. See what I’m getting at? A trap-door one-way function is what’s needed for Public Key cryptography, and exponentiation modulo a carefully constructed composite number is ideal for the purpose. First I create my own padlock by generating two 512 bit prime numbers p and q. I multiply them together to create a 1024 bit n. Now n is my padlock, p and q together are my key. (Note here that the padlock analogy breaks down in one significant way - it costs nothing to make and distribute multiple copies of n). To send me a message m, calculate and transmit m3 mod n. That’s the message padlocked into a box. Only I, knowing p and q, can spring the lock, by application of the secret “cube-rooting” exponent, calculated as 3-1 mod (p1)(q-1). Note that the message m could be itself a key, so RSA can be used for secure key exchange as well. A couple of important points about the practical implementation of RSA The primes p and q should be formed so that p-1 and q-1 are not smooth, that is it does not have only small prime factors. One (perhaps extreme) solution would be to make them both safe primes. This prevents a number of attacks. In the past quite elaborate procedures were proposed for prime generation, both to make factorisation of the modulus as difficult as possible and to prevent various attacks. It was suggested at one time that p+1 and q+1 should each have a large factor, as should [(p-1)/2]-1 and [(q1)/2]-1. These requirements are now known to be spurious. Furthermore restrictions of this type introduce another danger, as if we are too picky about the primes we choose, then an opponent, knowing our method, has only a restricted set of primes to search among. In fact purely random primes are probably as good as any, but a quick check that p-1 and q-1 are not smooth is still recommended. For example if they can be fully factored by trial division, then p and q are OK. The choice of 3 as an encryption exponent is not actually ideal, and causes a few problems. For a start it is important that the “cubed” message suffers modular reduction mod n, otherwise it may be recovered by simple integer techniques. For example 23 mod n is 8, and the cube root of 8 is trivially 2. Also if the same message is broadcast to three or more correspondents, then an eavesdropper can reconstruct the actual value of m3 (not mod anything) by application of the Chinese Remainder Theorem, and again find its integer cube root, the message m. However any other (odd) encryption exponent may be used. A small prime is good as it is more likely to have an inverse mod (p-1)(q-1). The numbers 257 and 65537 are popular choices – they are prime, big enough to avoid these attacks, and have a binary representation with only two 1’s in it - which makes exponentiation more efficient. The same message will always encrypt to the same ciphertext. This actually leaks information - if someone observes the same ciphertext on two different days, then they may not know what the message is, but they do know that it is the same message as before. There are of course obvious ways of disguising this - one could for example pad the message with random data. Program 3.2 - RSA This program generates a prime pair and their product, and then encrypts and decrypts a short “message”, using the RSA method. Note the use of the Chinese remainder theorem to speed up decryption. Decryption is of course carried out by the entity that knows the factors p and q, so this knowledge can be used to advantage. #include <iostream.h> #include <stdlib.h> #include "algor.h" #define PBITS 14 // number of bits in p and q void main() { Big p,q,n,phi,m,e,d,c,rp,rq; // seed random number generator srand(3); e=257; // encryption exponent // generate two random primes do { p=safe_prime(PBITS); q=safe_prime(PBITS); n=p*q; phi=(p-1)*(q-1); } while (gcd(e,phi)!=1); d=inverse(e,phi); // good parameters found - encrypt message cout << "n= " << n << endl; m=42; cout << "Plaintext = " << m << endl; c=pow(m,e,n); cout << "Ciphertext = " << c << endl; // Decrypt using CRT rp=pow(c%p,d%(p-1),p); rq=pow(c%q,d%(q-1),q); m=crt(rp,p,rq,q); cout << "Message = " << m << endl; } Small RSA Worked example. Using exponent of 3, so p and q should both be 2 mod 3. Choose p= 11 and q= 5, so n = 55 To encrypt the message 42, C = 423 mod 55 = 3 To decrypt 3, using the Chinese remainder theorem, first find cube roots of 3 mod 11 and mod 5. 1/3 mod 10 = 7 (cube-rooting exponent, 1/3 mod p-1) 1/3 mod 4 = 3 So Mp = 37 mod 11 = 9 (cube root mod 11) Mq = 33 mod 5 = 2 Apply CRT c= 1/p mod q = 1/11 mod 5 = 1 t = 1*2 – 9 mod 5 = 3 M=3*11+9 = 42 Digital Signature, or Digital Sealing The RSA system allows the concept of a Digital Signature. Assume a scenario where Alice & Bob are in communication. Now for Alice to ‘sign’ a plaintext, she first ‘decrypts’ or signs it with her own private key, and then encrypts it with the Bob’s public key,. 1 3 C [ P mod na ] mod nb 3 At the other end Bob reconstructs the plaintext by first decrypting with his private key, hence stripping off the encryption, and then “encrypting” with Alice’s public key to strip off the signature. (This is also called signature verification.) 1 3 [C mod nb ] mod na P 3 If P makes sense, then only Alice could have sent it, as only Alice knows her private decryption key. Note that a public key can be used for both encryption and the verification of digital signature. The private key can be used for both decryption and digital signature. To Bob Message Alice Signs message …. …. and applies Bob’s Public key However this is not quite as nice as it seems. How does Alice know that Paddy hasn’t simply given me his public key, for which of course he has the private key, and pretended that it is Bob’s? These keys are large numbers that are difficult to remember. There is a need to securely associate a Public key with its owner. This is where Certification comes in. A certificate binds a public key to an individual. A Trusted Third Party provides a certificate to each individual involved. This consists of the users identity, other relevant information, and their public key. The complete certificate is then in turn digitally signed by the Trusted Third party, using their own public/private key pair. The TTP’s public key is “well-known” to all parties. So now to send you a message, I first sign the message with my own private key. I then access your certificate from a public directory. I check the validity of the certificate using the TTPs public key to verify the signature. Then I encrypt the message using your public key as extracted from the certificate. When you receive the ciphertext, you decrypt it using your private key, and then you verify my signature using my public key, which you get from my certificate. Now you know it must have come from me, and authentication is restored. This certifies Bob:Name: Bob Ratcliff Address: 4 Fred West Terrace Height: 6’ 7 Hair Colour: Brown This is his public key:- Bob’s Seal of Trusted Authority Now I can access Bob’s public key in such a way that I can trust that it really is Bob’s public key. Further more I am also in a position to verify his seal, or digital signature. X.509 specifies a standard for certificate format. Rabin’s method This is a variant of RSA which uses the exponent 2. Unfortunately it has a fatal Achilles heel - but nonetheless it is worthy of study. A message m is encrypted by calculating m2 mod n, for n = pq, where p and q are typically 512 bit prime numbers. The obvious disadvantage is that a ciphertext will have in general four square roots, only one of which will correspond to the original message. But if this were the only problem, it would not be insurmountable. The good news is that cracking a cryptosystem based on this idea is provably as difficult as factoring the modulus, because, as we have demonstrated, the ability to extract a square root of an arbitrary number mod n can be exploited to factor n. This is not the case with classic RSA - there may be a way of extracting cube or higher roots without factoring the modulus (although this is thought unlikely). Nevertheless on the face of it we can be more confident with the security of this approach, because of its proven equivalence to the difficulty of factoring. The bad news is - it has a fatal flaw. The fact is that simply making use of the decryption facility can reveal the factors of n. This is not true of RSA - I could let an enemy use my decryption facility to extract cube roots to their hearts content. This could not be exploited to factor my modulus. However such access to a square-rooting facility allows just that. This is called a chosenciphertext attack. Simply encrypt any random message r, by squaring it mod n and present it for decryption. Somehow get hold of the decrypt, and if it is not r, then out pop the factors. El Gamal Public Key Cryptography This PK system is a little more elaborate than RSA. It is based on the hardness of the discrete logarithm problem, rather than on integer factorisation. It can be looked on as an extension of the Diffie-Hellman key exchange algorithm. Using the same p as used for Diffie-Hellman I generate a 1024 bit public key y as y = 3x mod p I keep the 160 bit number x secret. To send me a message m, you generate a random 160 bit number k, and perform the following calculations:- c1 = 3k mod p c2 = m.yk mod p The data {c1,c2} is the ciphertext. The message m is effectively disguised in c2 by being multiplied by a number that an outsider cannot determine. However I, knowing x, can recover m as m = c2/c1x mod p This is easily verified by substituting for c1 and c2 from above. An outsider must, it appears, solve the discrete logarithm problem in order to break this system. Observe that the ciphertext is twice the size of the message - this is undoubtedly a disadvantage. But every cloud has a silver lining. Using this method the same message will not now encrypt to the same ciphertext, assuming it is associated each time with a different random value k. #include <iostream.h> #include <stdlib.h> #include "algor.h" #define PBITS 30 #define EBITS 12 void main() { Big p,c1,c2,m,k,pub,priv; // seed random number generator srand(4); // generate PBITS-bit safe prime p=safe_prime(PBITS); cout << "Prime = " << p << endl; // generate public/private key pair priv=rand(EBITS,2); pub=pow(3,priv,p); m=42; // encrypt message m k=rand(EBITS,2); c1=pow(3,k,p); c2=modmult(m,pow(pub,k,p),p); // decrypt message m=modmult(c2,inverse(pow(c1,priv,p),p),p); cout << "message= " << m << endl; } An alternative approach, which can also be used with the Diffie-Hellman key exchange, is to use instead of a primitive root, a generator g of a large subgroup of order q, where q is a 160-bit prime that divides p-1. Such a g can be easily found, as r(p-1)/q mod p, assuming r is a known primitive root. This seems to be just as strong (although p is no longer “safe”). The modular inversion can be profitably avoided in this case by decrypting m as m = c2.c1 q-x mod p #include <iostream.h> #include <stdlib.h> #include "algor.h" #define QBITS 12 #define PBITS 30 void main() { Big p,q,m,t,g,c1,c2,priv,pub,k; // seed random number generator srand(5); // generate QBITS bit prime q q=rand(QBITS,2); while (!prime(q)) q++; cout << "sub-prime q= " << q << endl; // find PBITS bit prime p = 2*m*q+1 t=pow(2,PBITS)/(2*q); do { for (;;) { m=rand(t); p=2*m*q+1; if (prime(p)) break; } } while (digits(p,2)!=PBITS); cout << "prime p= " << p << endl; // get subgroup generator g do { /* find primitive root t */ t=rand(p-1); g=pow(t,(p-1)/q,p); } while (g==1); cout << "sub-group generator g= " << g << endl; // generate public/private key pair priv=rand(q); pub=pow(g,priv,p); cout << "Private key = " << priv << " Public Key = " << pub << endl; m=42; // encrypt message m k=rand(q); c1=pow(g,k,p); c2=modmult(m,pow(pub,k,p),p); // decrypt message m=modmult(c2,pow(c1,q-priv,p),p); cout << "message= " << m << endl; } Goldwasser-Micali The difficulty of establishing quadratic residuosity with respect to a number n=pq forms the basis of this public key method. I generate n from two secret primes p and q, just as for the RSA method. I make n public as well as a random quadratic non-residue y of n, constructed such that (y/p) = (y/q) = -1. A QNR of this form is sometimes called a psuedo QR, as (y/n) evaluates as +1. To send me a message, break it down into individual bits, m0,m1,m2, etc. Encrypt the i-th bit as follows:Generate a random xi < n If mi = 0 send me ci = xi2 mod n. If mi = 1 send me ci = y.xi2 mod n. I alone can figure out the value of each bit, by checking whether or not the received value is a truly a QR, by evaluating (ci/p). An outsider can of course evaluate (ci/n), but this will always be +1, and so conveys no information. Two points need to be made: This is not a practicable Public Key system, as, for typical security parameters each message bit generates perhaps 1024 bits of ciphertext. This is quite unacceptable. This is a probabilistic Public Key method. The same message will encrypt differently each time, due to the random xi values associated with each bit. This is an advantage with respect to RSA. Although not a practicable system, it does illustrate the potential of the exploiting quadratic residuosity. Blum-Blum-Shub random number generator What are the ideal properties of a pseudo-random number generator? In the past various mathematical formulae have been suggested which appear to generate random-looking numbers, and which have then been subjected to a battery of arcane statistical tests, with names like the Poker test, the Chisquared test, the Kolmogorov-Smirnov test, etc. In fact there is a way to short-circuit all of that. A good random number generator that will pass all conceivable statistical tests need have just one property – it should be unpredictable. Consider now the simple iteration x x2 mod n where n is the product of two 512-bit primes p and q, both congruent to 3 mod 4. In this case there is only one of the four square roots of a quadratic residue that is itself a quadratic residue – the principle square root. So the series of values generated by this iteration are uniquely defined in both directions – to the right by squaring mod n, to the left by finding the unique principal square root. In essence this iteration takes us on a random tour through the quadratic residues. Consider now the sequence of bits generated by examining the least significant bit of the value of x after each iteration, which might be, for example 0 1 1 0 1 0 1 1 0 0 0 1 0 1 1 …… Consider the predictability of this sequence, looked at initially backwards from right to left. If I were able to predict the next bit to the left, then I would be predicting the least significant bit of the square root of the current value of x. And if I could do that then I could factor n. Therefore the unpredictability of the bit sequence is nicely predicated on the difficulty of factoring n. Put another way, if such bits could be predicted with accuracy any better than 5050, then it follows that factoring a 1024-bit number is easy. But it isn’t so, well, draw your own conclusions. Unpredictability to the right depends on not being able to guess the initial value of x, and if this is an unknown 1024-bit value then this will clearly not be possible. Example: Consider n=437=19*23. Now 6 is a QR mod 437 and has 4 square roots 81, 356, 195 and 242. Of these 81 is the principal square root. Note that (81/19) = (81 mod 19/19) = (5/19) = 59 mod 19 = +1. Also (81/23) = (12/23) = 1211 mod 23 = +1. Its principal square root is 9. The principal square root of 9 is 250…. etc. x x2 x x2 x2 x x2 x 1 1 2 4 3 9 4 16 5 25 6 36 7 49 8 64 9 81 13 17 21 25 29 169 289 4 188 404 10 14 18 22 26 30 100 196 324 47 239 26 11 15 19 23 27 31 121 225 361 92 292 87 12 16 20 24 28 32 144 256 400 139 347 150 33 37 41 45 49 53 57 61 65 69 73 77 215 58 370 277 216 187 190 225 292 391 85 248 34 38 42 46 50 54 58 62 66 70 74 78 282 133 16 368 315 294 305 348 423 93 232 403 35 39 43 47 51 55 59 63 67 71 75 79 351 210 101 24 416 403 422 36 119 234 381 123 36 422 40 44 48 52 56 60 64 68 72 76 80 289 188 119 82 77 104 163 254 377 95 282 81 6 85 89 93 97 101 105 109 113 233 55 346 232 150 100 82 96 82 86 90 94 98 102 106 110 114 169 404 234 96 427 353 311 301 323 83 87 91 95 99 103 107 111 115 334 140 415 285 187 121 87 85 115 84 88 92 96 100 104 108 112 116 64 315 161 39 386 328 302 308 346 117 121 125 129 133 137 141 145 149 153 157 161 165 169 173 177 181 185 189 193 197 201 205 142 220 330 35 209 415 216 49 351 248 177 138 131 156 213 302 423 139 324 104 353 197 73 118 122 126 130 134 138 142 146 150 154 158 162 166 170 174 178 182 186 190 194 198 202 206 377 26 144 294 39 253 62 340 213 118 55 24 25 58 123 220 349 73 266 54 311 163 47 119 177 123 127 131 135 139 143 147 151 155 159 163 167 171 175 179 183 187 191 195 199 203 207 271 397 118 308 93 347 196 77 427 372 349 358 399 35 140 277 9 210 6 271 131 23 120 124 128 132 136 140 144 148 152 156 160 164 168 172 176 180 184 188 192 196 200 204 208 416 81 215 381 142 372 197 54 380 301 254 239 256 305 386 62 207 384 156 397 233 101 1 209 213 217 221 225 418 358 330 334 210 214 218 222 400 348 328 340 211 215 219 223 384 340 328 348 212 216 220 224 370 334 330 358 370 226 230 234 238 242 246 384 23 131 271 6 210 227 231 235 239 243 247 400 47 163 311 54 266 228 232 236 240 244 248 418 73 197 353 104 324 251 255 259 263 267 271 275 279 283 287 291 295 299 303 307 311 315 319 323 327 331 335 339 343 347 351 355 359 363 367 73 349 220 123 58 25 24 55 118 213 340 62 253 39 294 144 26 377 323 301 311 353 427 96 234 404 169 403 232 93 252 256 260 264 268 272 276 280 284 288 292 296 300 304 308 312 316 320 324 328 332 336 340 344 348 352 356 360 364 368 139 423 302 213 156 131 138 177 248 351 49 216 415 209 35 330 220 142 96 82 100 150 232 346 55 233 6 248 85 391 371 375 379 383 387 391 395 399 403 407 411 415 419 423 348 305 294 315 368 16 133 282 26 239 47 324 372 376 380 384 388 392 396 400 404 408 412 416 420 292 225 190 187 216 277 370 58 215 404 188 4 289 423 427 431 435 196 100 36 4 424 428 432 436 169 81 25 1 229 233 237 241 245 1 101 233 397 156 249 253 257 261 265 269 273 277 281 285 289 293 297 301 305 309 313 317 321 325 329 333 337 341 345 349 353 357 361 365 384 207 62 386 305 256 239 254 301 380 54 197 372 142 381 215 81 416 346 308 302 328 386 39 161 315 64 282 95 377 250 9 254 258 262 266 270 274 278 282 286 290 294 298 302 306 310 314 318 322 326 330 334 338 342 346 350 354 358 362 366 277 140 35 399 358 349 372 427 77 196 347 93 308 118 397 271 177 115 85 87 121 187 285 415 140 334 123 381 234 369 373 377 381 385 389 393 397 401 405 409 413 417 254 163 104 77 82 119 188 289 422 150 347 139 400 370 119 374 378 382 386 390 394 398 402 406 410 414 418 36 422 403 416 24 101 210 351 87 292 92 361 421 425 429 433 256 144 64 16 422 225 426 430 434 121 49 9 Now start with x=250 and keep squaring and keep the least significant bit… This random number generator obviously comes very close to the ideal of that required by a one-time pad. Generate two suitable primes p and q and multiply them to obtain n. Then destroy p and q - ideally this could all be done inside a computer program which simply outputs n so that p and q are never seen. To create a pseudo-one-time pad, distribute an initial value of x, perhaps using the Diffie-Hellman method. Then XOR the least significant bit of x after each iteration, with the next bit of the message. Breaking such a system is provably equivalent to factoring a 1024-bit number, a task considered at present to be completely computationally infeasible. There are two potential shortcomings. First the method is rather inefficient – each random bit produced requires a modular squaring of a 1024-bit number. In fact it has been proved that up to lg (lg n) least significant bits can be extracted simultaneously for use, without weakening the method. So if n is 1024 bits, then the 10 least significant bits can be used after each iteration – a 1000% improvement. In fact it has been conjectured that up to half the bits can be safely used – but if we do so we loose our proof of equivalence with factoring, which is the whole point of the method. The second issue is that of cycle length. All deterministic pseudo-random number generators start to repeat eventually. However it turns out that if the values of x generated by repeated modular squaring mod n start to cycle, then this cycling could be easily exploited to factor n. So, based on our working assumption that factoring is hard, we can further assume that cycling will never occur. Program 3.5 – Blum-Blum-Shub pseudo random number generator #include <iostream.h> #include <stdlib.h> #include "algor.h" #define PBITS 14 void main() { Big x,p,q,n; // seed random number generator srand(5); // generate two PBITS-bit safe primes p=safe_prime(PBITS); q=safe_prime(PBITS); n=p*q; p=0; q=0; // destroy p and q x=rand(2*PBITS,2); for (int i=0;i<70;i++) { x=modmult(x,x,n); cout << (x&1); // output least significant bit } } Blum-Goldwasser PK system The Blum-Blum-Shub cryptographically strong number random number generator can be converted into a Public Key Method. The initial set-up is similar to RSA. A public key n is formed as the product of two primes p and q, this time both congruent to 3 mod 4. The composite n constitutes the public key, and the two prime factors are the private key. The idea is now quite simple. To send me a message, generate a random initial value for x, and start squaring it mod my public key n. Use the resulting BBS generator as a onetime pad to encrypt the message. Then send me The encrypted message The length of the message m The final value of xm, after one last squaring mod n. To reconstruct the message, I can use my secret knowledge of p and q to “rewind” the one time-pad to its beginning, and run it again over the ciphertext, thus revealing the message. Specifically I can use my knowledge of p and q to calculate repeated square roots of the final value of x, until it has the same value it had initially. I can now run the pad forward again to decrypt the message. If the message consisted of m bits (assuming only the least significant bit of x is being used for encryption), then I must rewind the generator back m steps. One way would be to find m square roots, one after the other. But in fact I can jump straight back to the beginning in just one step, and as I know p and q the Chinese remainder theorem is relevant. Calculate x p xm [( p 1) / 4 ]m mod p 1 mod p Next calculate xq in a similar fashion, and combine the values of xp and xq using the CRT. The value obtained is the initial value of x used to encrypt the message. After this complex initial calculation, things proceed very much as for encryption. The pad is run forward again over the ciphertext, in effect stripping off the encryption and revealing the original message. As a PK system, this method is in many ways superior to RSA. In particular it is far more efficient in terms of bits encrypted per second, particularly if used to encrypt a very long message. It is, like the impractical Goldwasser-Micali method a naturally probabilistic PK system, as the same message will not encrypt to the same ciphertext, due to the encryptor’s random initial choice of x. There is however, sadly, a fly in the ointment. Since the decrypting process now has the capacity to calculate square roots mod n, it can be abused to reveal the factors of n – using basically the same chosen ciphertext attack that rendered the Rabin method vulnerable. Note that this attack is possible even though the decrypting process might reveal only a few bits of a square roots at a time – recall that the ability to consistently determine even a bit of a square root can, by repeated invocation, be used to factor n. 1 So it turns out again that a method based on the difficulty of extracting square roots and hence equivalent to factoring the modulus, falls again to a chosen ciphertext attack, which turns this apparent strength into a weakness. This flaw does not affect the security of the BBS generator, for which of course no decrypting process exists. In that case, since p and q have been destroyed, any technique that recovers them constitutes a bone fide factoring algorithm. 1 We can however fix things, after a fashion. Choose p and q now to be congruent to 2 mod 3, and replace the basic BBS iteration with x x3 mod n This works just as well, except that its security now depends, not on the difficulty of factoring, but rather on an instance of the weaker RSA assumption, that is the difficulty of extracting cube roots mod n without knowledge of the factors of n. Again the lg( lg n) least significant bits are simultaneously secure (under this assumption). Encryption proceeds as before, using this new iteration. To rewind this generator prior to decryption calculate x p xm [( 2 ( p 1) 1) / 3]m mod p 1 mod p And similarly xq. Combining these values via the CRT gives the same value of x as could have been obtained (less efficiently) by serially extracting m cube roots of the final value of x that comes with the encrypted message. Now we finally have a perfectly viable probabilistic PK system. It hasn’t proved as popular as RSA for a number of reasons: Its improved efficiency is not relevant in most applications, where only only a short message is to be encrypted. It encrypts as a stream cipher using simple XOR. This is vulnerable to a substitution attack. Classic RSA encrypts as a block cipher. #include <iostream.h> #include <stdlib.h> #include "algor.h" #define PBITS 14 char message[]="This is a test of the Blum-Goldwasser probabalistic PK system"; void main() { int i,m; Big x,p,q,n,xp,xq,e; // seed random number generator srand(54); // generate two PBITS-bit safe primes p=safe_prime(PBITS); q=safe_prime(PBITS); n=p*q; // encrypt message x=rand(PBITS,2); // random x for (m=0;message[m]!=0;m++) { x=pow(x,3,n); message[m]^=(char)x; // XOR with least // significant byte of x } cout << "Ciphertext= \n" << message << endl; x=pow(x,3,n); // once more // decrypt message // first recover pad e=pow((2*(p-1)+1)/3,m+1,p-1); xp=pow(x,e,p); e=pow((2*(q-1)+1)/3,m+1,q-1); xq=pow(x,e,q); x=crt(xp,p,xq,q); // combine with CRT for (i=0;i<m;i++) { x=pow(x,3,n); message[i]^=(char)x; // XOR with least // significant byte of x } cout << "Message= \n" << message << endl; }