사용자 도구

사이트 도구


kb:scopalgorithm

SCOP Algorithm

see The SCOP Stream Cipher by Simeon V. Maltchev, Peter T. Antonov

소스

////////////////////////////////////////////////////////////////////////////////
/// \class cScopStream
/// \brief "SCOP"라는 Stream Cipher 알고리즘 구현.
///
/// Simeon Maltchev의 문서에 있는 소스를 대충 정리했다. 자세한 내용은 아래의
/// 링크를 참고하기 바란다.
///
/// http://www.geocities.com/smaltchev/scop.html
////////////////////////////////////////////////////////////////////////////////
 
class cScopStream
{
private:
    struct st_key
    { 
        UINT32 v[384];
        UINT8  i;
        UINT8  j;
        UINT8  t3;
    }; 
 
    struct st_gp8
    { 
        UINT8  coef[8][4];
        UINT32 x[4];
    }; 
 
    st_key m_Key; 
    st_gp8 m_Internal; 
 
 
public:
    cScopStream(UINT8* key, UINT32 key_size)
    {
        UINT32 odd; 
        UINT32 t[4]; 
 
        ExpandKey(key, key_size); 
 
        for (int i = 0; i < 8; i++) 
            GeneratePolynoms(t); 
 
        for (int i = 0; i < 12; i++) 
        { 
            for (int j = 0; j < 8; j++) 
                GeneratePolynoms(m_Key.v + i * 32 + j * 4); 
 
            GeneratePolynoms(t); 
        } 
 
        GeneratePolynoms(t); 
        m_Key.i  =(UINT8)(t[3] >> 24); 
        m_Key.j  =(UINT8)(t[3] >> 16); 
        m_Key.t3 =(UINT8)(t[3] >> 8); 
 
        odd = t[3] & 0x7F; 
        m_Key.v[odd] |= 1; 
    }
 
    virtual ~cScopStream() {}
 
 
public:
    void Encrypt(UINT32* buf, int buflen)
    {
        UINT8   i    = m_Key.i;
        UINT8   j    = m_Key.j; 
        UINT32  t1   = 0;
        UINT32  t2   = 0;
        UINT32  t3   = m_Key.t3; 
        UINT32  k    = 0;
        UINT32  t    = 0; 
        UINT32* word = buf;
        UINT32* v    = m_Key.v; 
 
        while (word < buf + buflen) 
        { 
            t1 = v[128 + j]; 
            j  = j + static_cast<UINT8>(t3); 
            t  = v[i]; 
            t2 = v[128 + j]; 
 
            /* If you want to compile with Borland's 32-bit C compiler using 
            optimizations, change the line below to: 
            i =(i + 1) & 255; */ 
            i++; 
 
            t3 = t2 + t; 
            v[128 + j] = t3; 
            j = j + static_cast<UINT8>(t2); 
            k  = t1 + t2; 
 
            *word++ += k; 
        } 
    }
 
    void Decrypt(UINT32* buf, int buflen)
    {
        UINT32  k    = 0;
        UINT32  t    = 0; 
        UINT8   i    = m_Key.i; 
        UINT8   j    = m_Key.j; 
        UINT32  t1   = 0;
        UINT32  t2   = 0;
        UINT32  t3   = m_Key.t3; 
        UINT32* v    = m_Key.v; 
        UINT32* word = buf; 
 
        while (word < buf + buflen) 
        { 
            t1 = v[128 + j]; 
            j  = j + static_cast<UINT8>(t3); 
            t  = v[i]; 
            t2 = v[128 + j]; 
 
            // If you want to compile with Borland's 32-bit C compiler
            // using optimizations, change the line below to: 
            // i =(i + 1) & 255;
            i++; 
 
            t3 = t2 + t; 
            v[128 + j] = t3; 
            j = j + static_cast<UINT8>(t2); 
            k  = t1 + t2;
 
            *word++ -= k; 
        } 
    }
 
 
private:
    void ExpandKey(UINT8* in, UINT32 in_size)
    {
        Assert(in_size >= 2 && in_size <= 48); 
 
        UINT8* p = reinterpret_cast<UINT8*>(&m_Internal); 
 
        for (UINT32 i = 0; i < in_size; i++) 
            p[i] = in[i]; 
 
        for (UINT32 i = in_size; i < 48; i++) 
            p[i] =(UINT8)(p[i - in_size] + p[i - in_size + 1]); 
 
        UINT8 counter = 1; 
        for (UINT32 i = 0; i < 32; i++) 
        { 
            if(p[i] == 0) 
                p[i] = counter++; 
        } 
    }
 
    void GeneratePolynoms(UINT32* out)
    {
        UINT32 y1, y2;
        UINT32 x_1, x_2, x_3, x_4; 
        UINT32 newx[4]; 
        int i, i2; 
 
        for (i = 0; i < 8; i += 2) 
        { 
            i2 = i >> 1; 
 
            x_1 = m_Internal.x[i2] >> 16; 
            x_2 = x_1 * x_1; 
            x_3 = x_2 * x_1; 
            x_4 = x_3 * x_1; 
 
            y1 = m_Internal.coef[i][0] * x_4 + 
                m_Internal.coef[i][1] * x_3 + 
                m_Internal.coef[i][2] * x_2 + 
                m_Internal.coef[i][3] * x_1 + 1; 
 
            x_1 = m_Internal.x[i2] & 0xFFFFL; 
            x_2 = x_1 * x_1; 
            x_3 = x_2 * x_1; 
            x_4 = x_3 * x_1; 
 
            y2 = m_Internal.coef[i + 1][0] * x_4 + 
                m_Internal.coef[i + 1][1] * x_3 + 
                m_Internal.coef[i + 1][2] * x_2 + 
                m_Internal.coef[i + 1][3] * x_1 + 1; 
 
            out[i2]  = (y1 << 16) | (y2 & 0xFFFFL); 
            newx[i2] = (y1 & 0xFFFF0000L) | (y2 >> 16); 
        } 
 
        m_Internal.x[0] = (newx[0] >> 16) | (newx[3] << 16); 
        m_Internal.x[1] = (newx[0] << 16) | (newx[1] >> 16); 
        m_Internal.x[2] = (newx[1] << 16) | (newx[2] >> 16); 
        m_Internal.x[3] = (newx[2] << 16) | (newx[3] >> 16); 
    }
};

샘플

#!cpp
UINT8 mykey[] = { 
    0x29, 0x04, 0x19, 0x72, 0xFB, 0x42, 0xBA, 0x5F,  
    0xC7, 0x12, 0x77, 0x12, 0xF1, 0x38, 0x29, 0xC9 
}; 
 
cScopStream stream1(mykey, sizeof(mykey));
cScopStream stream2(mykey, sizeof(mykey));
 
UINT32 original[] = { 100, 200, 300, 400, 500, 600 };
UINT32 dest[]     = { 100, 200, 300, 400, 500, 600 };
 
stream1.Encrypt(dest, 6);
stream2.Decrypt(dest, 6);
 
for (int i=0; i<6; ++i)
{
    if (original[i] != dest[i])
    {
        Assert(false);
    }
}

kb/scopalgorithm.txt · 마지막으로 수정됨: 2014/11/09 20:29 (바깥 편집)