001/**
002 *
003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either 
008 * version 2.1 of the License, or (at your option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013 * Lesser General Public License for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public 
016 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
017 * 
018 **/
019package lucee.runtime.crypt;
020
021import lucee.commons.lang.StringUtil;
022
023public final class CFMXCompat {
024
025    public static final String ALGORITHM_NAME = "cfmx_compat";
026
027
028    private String m_Key;
029    private int m_LFSR_A = 0x13579bdf;
030    private int m_LFSR_B = 0x2468ace0;
031    private int m_LFSR_C = 0xfdb97531;
032    private int m_Mask_A = 0x80000062;
033    private int m_Mask_B = 0x40000020;
034    private int m_Mask_C = 0x10000002;
035    private int m_Rot0_A = 0x7fffffff;
036    private int m_Rot0_B = 0x3fffffff;
037    private int m_Rot0_C = 0xfffffff;
038    private int m_Rot1_A = 0x80000000;
039    private int m_Rot1_B = 0xc0000000;
040    private int m_Rot1_C = 0xf0000000;
041    
042
043    public byte[] transformString(String key, byte inBytes[]) {
044        setKey(key);
045        int length = inBytes.length;
046        byte outBytes[] = new byte[length];
047        for(int i = 0; i < length; i++) {
048            outBytes[i] = transformByte(inBytes[i]);
049        }
050        return outBytes;
051    }
052
053    private byte transformByte(byte target) {
054        byte crypto = 0;
055        int b = m_LFSR_B & 1;
056        int c = m_LFSR_C & 1;
057        for(int i = 0; i < 8; i++) {
058            if(0 != (m_LFSR_A & 1)) {
059                m_LFSR_A = m_LFSR_A ^ m_Mask_A >>> 1 | m_Rot1_A;
060                if(0 != (m_LFSR_B & 1)){
061                    m_LFSR_B = m_LFSR_B ^ m_Mask_B >>> 1 | m_Rot1_B;
062                    b = 1;
063                } 
064                else{
065                    m_LFSR_B = m_LFSR_B >>> 1 & m_Rot0_B;
066                    b = 0;
067                }
068            } 
069            else{
070                m_LFSR_A = m_LFSR_A >>> 1 & m_Rot0_A;
071                if(0 != (m_LFSR_C & 1)) {
072                    m_LFSR_C = m_LFSR_C ^ m_Mask_C >>> 1 | m_Rot1_C;
073                    c = 1;
074                } 
075                else{
076                    m_LFSR_C = m_LFSR_C >>> 1 & m_Rot0_C;
077                    c = 0;
078                }
079            }
080            crypto = (byte)(crypto << 1 | b ^ c);
081        }
082        target ^= crypto;
083        return target;
084    }
085
086    private void setKey(String key) {
087        int i = 0;
088        m_Key = key;
089        if(StringUtil.isEmpty(key)) key = "Default Seed";
090        char Seed[] = new char[key.length() >= 12 ? key.length() : 12];
091        m_Key.getChars(0, m_Key.length(), Seed, 0);
092        int originalLength = m_Key.length();
093        for(i = 0; originalLength + i < 12; i++)
094            Seed[originalLength + i] = Seed[i];
095
096        for(i = 0; i < 4; i++) {
097            m_LFSR_A = (m_LFSR_A <<= 8) | Seed[i + 4];
098            m_LFSR_B = (m_LFSR_B <<= 8) | Seed[i + 4];
099            m_LFSR_C = (m_LFSR_C <<= 8) | Seed[i + 4];
100        }
101        if(0 == m_LFSR_A)m_LFSR_A = 0x13579bdf;
102        if(0 == m_LFSR_B)m_LFSR_B = 0x2468ace0;
103        if(0 == m_LFSR_C)m_LFSR_C = 0xfdb97531;
104    }
105
106
107    /**
108     * returns true if the passed value is empty or is CFMX_COMPAT
109     */
110    public static boolean isCfmxCompat( String algorithm ) {
111
112        if ( StringUtil.isEmpty( algorithm, true ) )
113            return true;
114
115        return algorithm.equalsIgnoreCase( CFMXCompat.ALGORITHM_NAME );
116    }
117}