| Home Page | Recent Changes

RSA

R.S.A. stands for Rivest, Shamir and Adleman - the three cryptographers who invented this public key cryptosystem.

For information about RSA encryption see Wikipedia logo RSA and the related documents section below.

Code

This code uses integers, integers are 32bit in UnrealScript. Because of this the encryption as shown in the document isn't very secure. The improved code can have encryption up to 23bit, the previous implementation was limited to 13bits.

Using floats is not an option because they will lose signification at a certain point.

PowerMod

Support function to calculate b^e mod m. Because float signification you can't just use C**D%N

static final function int PowerMod(int C, int D, int N)
{
    local int p;
    c = mod(c, n);
    if (c < 0) c += n;
    p = 1;
    while (d >= 1)
    {
        if ((d & 1) == 1) p = mulmod(c, p, n);
        c = mulmod(c, c, n);
        d = d / 2;
    }
    return p;
}

static final function int mulmod(int C, int D, int N)
{
    local int p;
    c = mod(c, n);
    if (c < 0) c += n;
    p = 0;
    while (d >= 1)
    {
        if ((d & 1) == 1) p = mod(c + p, n);
        c = mod(c * 2, n);
        d = d / 2;
    }
    return p;
}

/**
 * int precision modulo function.
 * Like the % operator, this function returns a negative result for negative a.
 */
static final function int mod(int a, int n)
{
    return a - (a / n) * n;
}

_RSAGCD

A private function to calculate the Greatest Common Divider, this is use to calculate the encryption key

static final private function int _RSAGCD(int e, int PHI)
{
    local int great, a;
    if (e > PHI)
    {
        while (mod(e, PHI) != 0)
        {
            a = mod(e, PHI);
            e = PHI;
            PHI = a;
        }
        great = PHI;
    }
    else {
        while (mod(PHI, e) != 0)
        {
            a = mod(PHI, e);
            PHI = e;
            e = a;
        }
        great = e;
    }
    return great;
}

RSAEncodeKeygen

This method will calculate the encryption key E from the prime numbers you supply.

P and Q have to be prime and unequal. N=P*Q and must be large enough to contain all possible values you need to encrypt..

static final function int RSAPublicKeygen(int p, int q)
{
    local int PHI, E, great;
    PHI = (p-1)*(q-1);
    great = 0;
    E = 2;
    while (great != 1)
    {
        E++;
        great = _RSAGCD(E, PHI);
    }
    return E;
}

RSADecodeKeygen

This will calculate the decrypt key D for the corresponding encrypt key

Use the same P and Q as you did with the encrypt key

static final function int RSAPrivateKeygen(int E, int p, int q)
{
    local int PHI, u1, u2, u3, v1, v2, v3, t1, t2, t3, z;
    PHI = (p-1)*(q-1);
    u1 = 1;
    u2 = 0;
    u3 = PHI;
    v1 = 0;
    v2 = 1;
    v3 = E;
    while (v3 != 0)
    {
        z = u3/v3;
        t1 = u1-z*v1;
        t2 = u2-z*v2;
        t3 = u3-z*v3;
        u1 = v1;
        u2 = v2;
        u3 = v3;
        v1 = t1;
        v2 = t2;
        v3 = t3;
    }
    if (u2 < 0)
    {
        return u2 + PHI;
    }
    else {
        return u2;
    }
}

NumBits

This will return the number of bits used in an integer.

static final function int NumBits(int sample)
{
    local int bits;
    bits = 0;
    while (sample > 0)
    {
        sample = sample >>> 1;
        bits++;
    }
    return bits;
}

RSAEncodeStream

This will encode the string using the keys E and N (=P*Q). the output will be stored in the int array data2.

It will automactially adjust to window size according to the size of N. When N is more than 15 bits two characters will put in a single integer.

static final function RSAEncodeStream(coerce string data, int E, int N, out array<int> data2)
{
    local int i, c, window, j;
    window = NumBits(N)/8;
    for (i = 0; i < len(data); i = i+window)
    {
        c = 0;
        for (j = 0; j < window; j++)
        {
            c += Asc(Mid(data,i+j,1)) << (window-j-1)*8;
        }
        data2[data2.length] = PowerMod(c,E,N);
    }
}

RSADecodeStream

This will decrypt the array data to the correct string value.

It will automactially adjust to window size according to the size of N.

static final function string RSADecodeStream(array<int> data, int D, int N)
{
    local int i, c, window;
    local string result;
    window = NumBits(N)/8;
    for (i = 0; i < data.length; i++)
    {
        c = PowerMod(data[i],D,N);
        if (window > 3) result $= chr((c & 0xff000000) >> 24);
        if (window > 2) result $= chr((c & 0x00ff0000) >> 16);
        if (window > 1) result $= chr((c & 0x0000ff00) >> 8);
        result $= chr((c & 0x000000ff));
    }
    return result;
}

Example usage

Here's an example that creates the keys, encrypts and decrypts and checks if they're equal. It will also print the encrypted data.

function bool EncTest(int p, int q, string testData)
{
    local string s2;
    local int n,e,d;
    local array<int> ia;

    n = p*q;

    if (NumBits(N) < 8)
    {
        warn("Not enough bits for encrypting the data");
        return false;
    }

    e = RSAEncodeKeygen(p, q);
    d = RSADecodeKeygen(e, p, q);

    log("p="$p@"q="$q@"n="$n@"e="$e@"d="$d@"bits="$NumBits(N));

    log("Source:"$chr(9)$chr(9)@testData);
    RSAEncodeStream(testData, e, n, ia);
    log("Encrypted:"$chr(9)@printByteArray(ia));
    s2 = RSADecodeStream(ia, d, n);
    log("Decrypted:"$chr(9)@s2);

    return s2 == testData;
}

When called with EncTest(2851, 2927, "012345 hello world") it will output:

 p=2851 q=2927 n=8344877 e=13 d=2565877 bits=23
 Source:          012345 hello world
 Encrypted:       001075070001d062007efb6800542d6800471922003fc53e00692eae005a3a310074b044
 Decrypted:       012345 hello world

Note that I left in the values of p and q in the above example. You should remove the usage of p and q when you no longer need them. When you have decided what p and q to use calculate the n, e and d values and use them in the rest of your code.

Comments

Sixpack_Shambler: Hmmmm....I've tried this code out and when I decrypt a string I don't even have to use the decrypt string to decrypt it, I just converted every signgle byte in the encrypted array to big string and it came out as EXACTLY the same string as what I put in :/

El Muerte: then you didn't pick correct prime numbers. I've improved the implementation, it can now encrypt up to 23bits, thus allowing a window size of 2 bytes.

UsAaR33: Do you think it would be possible to perhaps rewrite some math algorithms? With structures and some funky overloading, you could probably use much higher bit encryption. Right now, you can factor out the private key in seconds...

El Muerte: both me and PJMODOS once started on an BigInt implementation, but neither of use ever finished it (at least not ebough to have all required operators). But it should be possible to create a BigInt type, but it won't be as nice\fast as a C or Pascal implementation (w.r.t. normal execution time in unrealscript).

Related documents

Related Topics


Category Algorithm

The Unreal Engine Documentation Site

Wiki Community

Topic Categories

Recent Changes

Offline Wiki

Unreal Engine

Console Commands

Terminology

FAQs

Help Desk

Mapping Topics

Mapping Lessons

UnrealEd Interface

UnrealScript Topics

UnrealScript Lessons

Making Mods

Class Tree

Modeling Topics

Chongqing Page

Log In