Welcome!

Join our community of MMO enthusiasts and game developers! By registering, you'll gain access to discussions on the latest developments in MMO server files and collaborate with like-minded individuals. Join us today and unlock the potential of MMO server development!

Join Today!

Better AES Encryption

Elite Diviner
Joined
Apr 7, 2008
Messages
494
Reaction score
66
hello guys this following is a rewrite of odin aes encryption using bouncycastle and methods rename, so no need to download jce policy and copy it around just get the bouncycastle jar will do :) let me know if the following can be improved further more :) also this is based on v144

thanks Diamondo25 for the neat version in mapleshark

Code:
/*
    This file is part of the OdinMS Maple Story Server
    Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
               Matthias Butz <matze@odinms.de>
               Jan Christian Meyer <vimes@odinms.de>


    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation version 3 as published by
    the Free Software Foundation. You may not use, modify or distribute
    this program under any other version of the GNU Affero General Public
    License.


    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.


    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/


package tools;




import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Security;


import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;


import org.bouncycastle.jce.provider.BouncyCastleProvider;


import sun.security.provider.SecureRandom;


/*
 *  @author Frz
 *  @author Multo
 * 
 */


public class MapleAESOFB {
    private byte iv[];
    private Cipher cipher;
    private short mapleVersion;


    private static final byte[] secretKey = {
               0x46, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 
               0x3C, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte)
               0xA3, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte)
               0xB6, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte)
               0x2F, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte)
               0xAE, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 
               0x57, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte)
               0xB7, (byte) 0x00, (byte) 0x00, (byte) 0x00 };
    
    private static final byte[] shuffleKey = { (byte) 0xEC, (byte) 0x3F, (byte) 0x77, (byte) 0xA4, (byte) 0x45, (byte) 0xD0, (byte) 0x71, (byte) 0xBF, (byte) 0xB7, (byte) 0x98, (byte) 0x20, (byte) 0xFC,
        (byte) 0x4B, (byte) 0xE9, (byte) 0xB3, (byte) 0xE1, (byte) 0x5C, (byte) 0x22, (byte) 0xF7, (byte) 0x0C, (byte) 0x44, (byte) 0x1B, (byte) 0x81, (byte) 0xBD, (byte) 0x63, (byte) 0x8D, (byte) 0xD4, (byte) 0xC3,
        (byte) 0xF2, (byte) 0x10, (byte) 0x19, (byte) 0xE0, (byte) 0xFB, (byte) 0xA1, (byte) 0x6E, (byte) 0x66, (byte) 0xEA, (byte) 0xAE, (byte) 0xD6, (byte) 0xCE, (byte) 0x06, (byte) 0x18, (byte) 0x4E, (byte) 0xEB,
        (byte) 0x78, (byte) 0x95, (byte) 0xDB, (byte) 0xBA, (byte) 0xB6, (byte) 0x42, (byte) 0x7A, (byte) 0x2A, (byte) 0x83, (byte) 0x0B, (byte) 0x54, (byte) 0x67, (byte) 0x6D, (byte) 0xE8, (byte) 0x65, (byte) 0xE7,
        (byte) 0x2F, (byte) 0x07, (byte) 0xF3, (byte) 0xAA, (byte) 0x27, (byte) 0x7B, (byte) 0x85, (byte) 0xB0, (byte) 0x26, (byte) 0xFD, (byte) 0x8B, (byte) 0xA9, (byte) 0xFA, (byte) 0xBE, (byte) 0xA8, (byte) 0xD7,
        (byte) 0xCB, (byte) 0xCC, (byte) 0x92, (byte) 0xDA, (byte) 0xF9, (byte) 0x93, (byte) 0x60, (byte) 0x2D, (byte) 0xDD, (byte) 0xD2, (byte) 0xA2, (byte) 0x9B, (byte) 0x39, (byte) 0x5F, (byte) 0x82, (byte) 0x21,
        (byte) 0x4C, (byte) 0x69, (byte) 0xF8, (byte) 0x31, (byte) 0x87, (byte) 0xEE, (byte) 0x8E, (byte) 0xAD, (byte) 0x8C, (byte) 0x6A, (byte) 0xBC, (byte) 0xB5, (byte) 0x6B, (byte) 0x59, (byte) 0x13, (byte) 0xF1,
        (byte) 0x04, (byte) 0x00, (byte) 0xF6, (byte) 0x5A, (byte) 0x35, (byte) 0x79, (byte) 0x48, (byte) 0x8F, (byte) 0x15, (byte) 0xCD, (byte) 0x97, (byte) 0x57, (byte) 0x12, (byte) 0x3E, (byte) 0x37, (byte) 0xFF,
        (byte) 0x9D, (byte) 0x4F, (byte) 0x51, (byte) 0xF5, (byte) 0xA3, (byte) 0x70, (byte) 0xBB, (byte) 0x14, (byte) 0x75, (byte) 0xC2, (byte) 0xB8, (byte) 0x72, (byte) 0xC0, (byte) 0xED, (byte) 0x7D, (byte) 0x68,
        (byte) 0xC9, (byte) 0x2E, (byte) 0x0D, (byte) 0x62, (byte) 0x46, (byte) 0x17, (byte) 0x11, (byte) 0x4D, (byte) 0x6C, (byte) 0xC4, (byte) 0x7E, (byte) 0x53, (byte) 0xC1, (byte) 0x25, (byte) 0xC7, (byte) 0x9A,
        (byte) 0x1C, (byte) 0x88, (byte) 0x58, (byte) 0x2C, (byte) 0x89, (byte) 0xDC, (byte) 0x02, (byte) 0x64, (byte) 0x40, (byte) 0x01, (byte) 0x5D, (byte) 0x38, (byte) 0xA5, (byte) 0xE2, (byte) 0xAF, (byte) 0x55,
        (byte) 0xD5, (byte) 0xEF, (byte) 0x1A, (byte) 0x7C, (byte) 0xA7, (byte) 0x5B, (byte) 0xA6, (byte) 0x6F, (byte) 0x86, (byte) 0x9F, (byte) 0x73, (byte) 0xE6, (byte) 0x0A, (byte) 0xDE, (byte) 0x2B, (byte) 0x99,
        (byte) 0x4A, (byte) 0x47, (byte) 0x9C, (byte) 0xDF, (byte) 0x09, (byte) 0x76, (byte) 0x9E, (byte) 0x30, (byte) 0x0E, (byte) 0xE4, (byte) 0xB2, (byte) 0x94, (byte) 0xA0, (byte) 0x3B, (byte) 0x34, (byte) 0x1D,
        (byte) 0x28, (byte) 0x0F, (byte) 0x36, (byte) 0xE3, (byte) 0x23, (byte) 0xB4, (byte) 0x03, (byte) 0xD8, (byte) 0x90, (byte) 0xC8, (byte) 0x3C, (byte) 0xFE, (byte) 0x5E, (byte) 0x32, (byte) 0x24, (byte) 0x50,
        (byte) 0x1F, (byte) 0x3A, (byte) 0x43, (byte) 0x8A, (byte) 0x96, (byte) 0x41, (byte) 0x74, (byte) 0xAC, (byte) 0x52, (byte) 0x33, (byte) 0xF0, (byte) 0xD9, (byte) 0x29, (byte) 0x80, (byte) 0xB1, (byte) 0x16,
        (byte) 0xD3, (byte) 0xAB, (byte) 0x91, (byte) 0xB9, (byte) 0x84, (byte) 0x7F, (byte) 0x61, (byte) 0x1E, (byte) 0xCF, (byte) 0xC5, (byte) 0xD1, (byte) 0x56, (byte) 0x3D, (byte) 0xCA, (byte) 0xF4, (byte) 0x05,
        (byte) 0xC6, (byte) 0xE5, (byte) 0x08, (byte) 0x49};


    public MapleAESOFB(byte iv[], short mapleVersion) {
            Key pKey = new SecretKeySpec(secretKey, "AES");
            SecureRandom pRandom = new SecureRandom();
            pRandom.engineNextBytes(iv);
            Security.addProvider(new BouncyCastleProvider());
            try {
                cipher = Cipher.getInstance("AES/OFB/NoPadding", "BC");
                cipher.init(Cipher.ENCRYPT_MODE, pKey);
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (NoSuchProviderException e) {
                e.printStackTrace();
            } catch (NoSuchPaddingException e) {
                e.printStackTrace();
            } catch (InvalidKeyException e) {
                e.printStackTrace();
            }
            this.setIv(iv);
            this.mapleVersion = (short) (((mapleVersion >> 8) & 0xFF) | ((mapleVersion << 8) & 0xFF00));
    }


    private void setIv(byte[] iv) {
        this.iv = iv;
    }


    private static byte[] multiplyBytes(byte[] in, int count, int mul) {
        byte[] ret = new byte[count * mul];
        for (int x = 0; x < count * mul; x++) {
            ret[x] = in[x % count];
        }
        return ret;
    }


    public byte[] crypt(byte[] data) {
        int remaining = data.length;
        int llength = 0x5B0;
        int start = 0;
        while (remaining > 0) {
            byte[] myIv = multiplyBytes(this.iv, 4, 4);
            if (remaining < llength) {
                llength = remaining;
            }
            for (int x = start; x < (start + llength); x++) {
                if ((x - start) % myIv.length == 0) {
                    try {
                        byte[] newIv = cipher.doFinal(myIv);
                        for (int j = 0; j < myIv.length; j++) {
                            myIv[j] = newIv[j];
                        }
                    } catch (IllegalBlockSizeException e) {
                    } catch (BadPaddingException e) {
                    }
                }
                data[x] ^= myIv[(x - start) % myIv.length];
            }
            start += llength;
            remaining -= llength;
            llength = 0x5B4;
        }
        updateIv();
        return data;
    }


    private void updateIv() {
        this.iv = getNewIv(this.iv);
    }


    public byte[] getPacketHeader(int length) {
        int iiv = (iv[3]) & 0xFF;
        iiv |= (iv[2] << 8) & 0xFF00;
        iiv ^= mapleVersion;
        int mlength = ((length << 8) & 0xFF00) | (length >>> 8);
        int xoredIv = iiv ^ mlength;
        byte[] ret = new byte[4];
        ret[0] = (byte) ((iiv >>> 8) & 0xFF);
        ret[1] = (byte) (iiv & 0xFF);
        ret[2] = (byte) ((xoredIv >>> 8) & 0xFF);
        ret[3] = (byte) (xoredIv & 0xFF);
        return ret;
    }


    public static int getPacketLength(int packetHeader) {
        int packetLength = ((packetHeader >>> 16) ^ (packetHeader & 0xFFFF));
        packetLength = ((packetLength << 8) & 0xFF00) | ((packetLength >>> 8) & 0xFF);
        return packetLength;
    }


    public boolean checkPacket(byte[] packet) {
        return ((((packet[0] ^ iv[2]) & 0xFF) == ((mapleVersion >> 8) & 0xFF)) && (((packet[1] ^ iv[3]) & 0xFF) == (mapleVersion & 0xFF)));
    }


    public boolean checkPacket(int packetHeader) {
        byte packetHeaderBuf[] = new byte[2];
        packetHeaderBuf[0] = (byte) ((packetHeader >> 24) & 0xFF);
        packetHeaderBuf[1] = (byte) ((packetHeader >> 16) & 0xFF);
        return checkPacket(packetHeaderBuf);
    }


    public static byte[] getNewIv(byte oldIv[]) {
        byte[] newIv = {(byte) 0xf2, 0x53, (byte) 0x50, (byte) 0xc6};
        for (int x = 0; x < 4; x++) {
            Shuffle(oldIv[x], newIv);
        }
        return newIv;
    }
        
   private static byte[] Shuffle(byte inputValue, byte[] pIv) {
         byte input = inputValue;
         byte tableInput = shuffleKey[input];
         pIv[0] += (byte)(shuffleKey[pIv[1]] - input);
         pIv[1] -= (byte)(pIv[2] ^ tableInput);
         pIv[2] ^= (byte)(shuffleKey[pIv[3]] + input);
         pIv[3] -= (byte)(pIv[0] - tableInput);
         
         int Value = (int) (pIv[0]) & 0xFF | (pIv[1] << 8) & 0xFF00 | (pIv[2] << 16) & 0xFF0000 | (pIv[3] << 24) & 0xFF000000;
         Value = (Value >> 0x1D | Value << 0x03);
         
         pIv[0] = (byte)(Value & 0xFF);
         pIv[1] = (byte)((Value >> 8) & 0xFF);
         pIv[2] = (byte)((Value >> 16) & 0xFF);
         pIv[3] = (byte)((Value >> 24) & 0xFF);
        
         return pIv;
         
    }
}
 
BloopBloop
Joined
Aug 9, 2012
Messages
892
Reaction score
275
Might as well add the flags used to set different algorithm's. Also i am pretty sure the jit will optimize this to the same assembly as with the previous code.
 
BloopBloop
Joined
Aug 9, 2012
Messages
892
Reaction score
275
How is this better? Care to explain?

Also.. WTF?

I didn't even saw that one. And yes unless you (multo/extremedevil etc...) mind implementing some kind of different handling for all those different exceptions,better use one try catch

About what he changed:
Code:
 private static byte[] funnyShit(byte inputByte, byte[] in) {
        byte elina = in[1];
        byte anna = inputByte;
        byte moritz = funnyBytes[(int) elina & 0xFF];
        moritz -= inputByte;
        in[0] += moritz;
        moritz = in[2];
        moritz ^= funnyBytes[(int) anna & 0xFF];
        elina -= (int) moritz & 0xFF;
        in[1] = elina;
        elina = in[3];
        moritz = elina;
        elina -= (int) in[0] & 0xFF;
        moritz = funnyBytes[(int) moritz & 0xFF];
        moritz += inputByte;
        moritz ^= in[2];
        in[2] = moritz;
        elina += (int) funnyBytes[(int) anna & 0xFF] & 0xFF;
        in[3] = elina;
        int merry = ((int) in[0]) & 0xFF;
        merry |= (in[1] << 8) & 0xFF00;
        merry |= (in[2] << 16) & 0xFF0000;
        merry |= (in[3] << 24) & 0xFF000000;
        int ret_value = merry;
        ret_value = ret_value >>> 0x1d;
        merry = merry << 3;
        ret_value = ret_value | merry;
        in[0] = (byte) (ret_value & 0xFF);
        in[1] = (byte) ((ret_value >> 8) & 0xFF);
        in[2] = (byte) ((ret_value >> 16) & 0xFF);
        in[3] = (byte) ((ret_value >> 24) & 0xFF);
        return in;
    }

TO

Nexon names it "MorphKey",if someone cares
Code:
  private static byte[] Shuffle(byte inputValue, byte[] pIv) {
         byte input = inputValue;
         byte tableInput = shuffleKey[input];
         pIv[0] += (byte)(shuffleKey[pIv[1]] - input);
         pIv[1] -= (byte)(pIv[2] ^ tableInput);
         pIv[2] ^= (byte)(shuffleKey[pIv[3]] + input);
         pIv[3] -= (byte)(pIv[0] - tableInput);
         
         int Value = (int) (pIv[0]) & 0xFF | (pIv[1] << 8) & 0xFF00 | (pIv[2] << 16) & 0xFF0000 | (pIv[3] << 24) & 0xFF000000;
         Value = (Value >> 0x1D | Value << 0x03);
         
         pIv[0] = (byte)(Value & 0xFF);
         pIv[1] = (byte)((Value >> 8) & 0xFF);
         pIv[2] = (byte)((Value >> 16) & 0xFF);
         pIv[3] = (byte)((Value >> 24) & 0xFF);
        
         return pIv;
         
    }
 
Junior Spellweaver
Joined
Apr 20, 2013
Messages
103
Reaction score
24
You did not contribute the slightest bit in this code, yet you have guts of naming yourself the author of this.
Personally I think the version Diamondo made is quite the mess and I doubt if it's any better than the old odin code.
But as you copied it, I doubt mentioning the flaws to you wont help much.

Oww, and did you even test this? (I was actually going to ask if you benchmarked this, but never mind)
Code:
Value = (Value >> 0x1D | Value << 0x03);         
         pIv[0] = (byte)(Value & 0xFF);
         pIv[1] = (byte)((Value >> 8) & 0xFF);
         pIv[2] = (byte)((Value >> 16) & 0xFF);
         pIv[3] = (byte)((Value >> 24) & 0xFF);

I aint no Java pro, but I do not think this is how shuffling works in Java
 
Initiate Mage
Joined
Apr 23, 2015
Messages
4
Reaction score
1
If this was just because of the nuisance of having to copy those files everywhere, here is an alternative solution. (Requires Java 7+)

Add the following methods under the main method of server.Start

PHP:
    /**
     * Credits: ntoskrnl of StackOverflow
     * http://stackoverflow.com/questions/1179672/
     * 
     */
    private static void removeCryptographyRestrictions() {
        if (!isRestrictedCryptography()) {
            System.out.println("Cryptography restrictions removal not needed");
            return;
        }
        try {
            /*
             * Do the following, but with reflection to bypass access checks:
             *
             * JceSecurity.isRestricted = false;
             * JceSecurity.defaultPolicy.perms.clear();
             * JceSecurity.defaultPolicy.add(CryptoAllPermission.INSTANCE);
             */
            final Class<?> jceSecurity = Class.forName("javax.crypto.JceSecurity");
            final Class<?> cryptoPermissions = Class.forName("javax.crypto.CryptoPermissions");
            final Class<?> cryptoAllPermission = Class.forName("javax.crypto.CryptoAllPermission");


            final Field isRestrictedField = jceSecurity.getDeclaredField("isRestricted");
            isRestrictedField.setAccessible(true);
            isRestrictedField.set(null, false);


            final Field defaultPolicyField = jceSecurity.getDeclaredField("defaultPolicy");
            defaultPolicyField.setAccessible(true);
            final PermissionCollection defaultPolicy = (PermissionCollection) defaultPolicyField.get(null);


            final Field perms = cryptoPermissions.getDeclaredField("perms");
            perms.setAccessible(true);
            ((Map<?, ?>) perms.get(defaultPolicy)).clear();


            final Field instance = cryptoAllPermission.getDeclaredField("INSTANCE");
            instance.setAccessible(true);
            defaultPolicy.add((Permission) instance.get(null));


            System.out.println("\t\tSuccessfully removed cryptography restrictions");
        } catch (final Exception e) {
            System.err.println("\t\tFailed to remove cryptography restrictions");
            e.printStackTrace();
        }
    }


    private static boolean isRestrictedCryptography() {
        // This simply matches the Oracle JRE, but not OpenJDK.
        return "Java(TM) SE Runtime Environment".equals(System.getProperty("java.runtime.name"));
    }

Then add this line as the first line under the main method
PHP:
Start.removeCryptographyRestrictions();
 
Last edited:
Elite Diviner
Joined
Apr 7, 2008
Messages
494
Reaction score
66
The code was a rewrite to use bouncy castle etc, I'm still working on a better improvement and will update the thread once I find it better
 
Joined
Apr 10, 2008
Messages
4,087
Reaction score
1,265
The code was a rewrite to use bouncy castle etc, I'm still working on a better improvement and will update the thread once I find it better

I think you're looking at the wrong place. I doubt you even know what bouncy castle is, considering the fact you can't explain how this is this better than JCE. Let me tell you do this - performance wise it is the same. There's no real reason to use BC unless you really need it.. but you don't. You didn't even refactor the code, so there isn't a slight improvement here.

Like I said it before, Multo, instead of wasting your time googling you better waste it on studying new things and actually release something useful.

EDIT: Go ahead, dislike my post. This just proves you're here to release crap to gain e-fame and not learn or contribute anything. People like you are the reason this section lost its' good men.
 
Last edited:
Everything is possible~
Loyal Member
Joined
Jan 9, 2008
Messages
818
Reaction score
847
> sees mention about neat mapleshark code
> sees that AES transform is still the same

I suggest you also copy that code over, because the original mapleshark aes transform code was weird.
 
Back
Top