Модераторы: Poseidon
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> [C++]Алгоритмы шифрования DES, 3DES и ГОСТ, реализация на С++ 
:(
    Опции темы
Первокурсница
Дата 17.4.2009, 22:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 22
Регистрация: 26.4.2008
Где: Оренбург

Репутация: нет
Всего: нет



Доброго времени суток!  smile 
Пишу курсовую.... В ее рамках необходимо реализовать 3 алгоритма шифрования: DES, 3DES и ГОСТ. Исходными данными (то биш открытым текстом) является файл типа .txt, из которого будут поступать данные на вход алгоритма. Как я понимаю, он открывется в программе в бинарном виде, то биш:
Код

#include <fstream.h>
...
...
ifstream f("blabla.txt", ios::binary);
...
...

В случае DES, на вход алгоритма поступает 64-битный блок (ну в ГОСТ вродьб как тоже). smile  Как, в каком виде представить эти 64 бита, чтобы было удомно реализовывать раунды алгоритма? Завести структуру как новый тип данных? Битовое поле, обьединение???  smile 
Уверяю Вас, что все доступные в инете варианты кодов мной уже переварены, но не усвоены ("доступные" еще и в смысле, учитывающем мои далеко не виртуозные навыки и познания в практической криптографии и битовой арифметике, если ее можно так назвать).  smile 
Помогите пожалуйста! smile 
PM MAIL   Вверх
zim22
Дата 18.4.2009, 07:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


depict1
****


Профиль
Группа: Завсегдатай
Сообщений: 2682
Регистрация: 15.1.2009
Где: Украина

Репутация: 16
Всего: 69



Цитата(Первокурсница @  17.4.2009,  22:19 Найти цитируемый пост)
Как, в каком виде представить эти 64 бита, чтобы было удомно реализовывать раунды алгоритма?

Код

std::vector<bool> vb(64);
std::bitset<64> bs;
unsigned char buffer[8]; / 8 элементов по 8 бит каждый


<stdint.h> defines types like int16_t, uint32_t, int64_t

Это сообщение отредактировал(а) zim22 - 18.4.2009, 07:33


--------------------
PM MAIL   Вверх
Первокурсница
Дата 19.4.2009, 18:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 22
Регистрация: 26.4.2008
Где: Оренбург

Репутация: нет
Всего: нет



эммммм...  спасибо! smile 
PM MAIL   Вверх
zim22
Дата 20.4.2009, 11:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


depict1
****


Профиль
Группа: Завсегдатай
Сообщений: 2682
Регистрация: 15.1.2009
Где: Украина

Репутация: 16
Всего: 69



Цитата(Первокурсница @  17.4.2009,  22:19 Найти цитируемый пост)
Как, в каком виде представить эти 64 бита, чтобы было удомно реализовывать раунды алгоритма?

я не знаю что такое раунды алгоритма и как вы собираетесь оперировать битами. уточните условие задачи. 


--------------------
PM MAIL   Вверх
airyashov
Дата 20.4.2009, 14:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 284
Регистрация: 1.7.2008

Репутация: 1
Всего: 6



посмотрел свои задачи для ГОСТ использовал массивы из 32-битных элементов, чтобы было удобно делить на блоки и генерировать ключи


--------------------
icq:3(один)7748666
mail:airyashov( а )inbox.ru
PM MAIL   Вверх
Первокурсница
Дата 18.5.2009, 10:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 22
Регистрация: 26.4.2008
Где: Оренбург

Репутация: нет
Всего: нет



Добрый день! =)) С блоками разобрались (Использовала 64 и 32 битные целые, оказывается в С++ они определеныsmile)))... алгоритмы реализованы... вроде все правильно, алгоритм шифрует, получает значение... Это значение потом дешифруется тем же алгоритмом, но ключи применяются в обратном порядке... по всей логике вещей результат должен совпасть с исходным значением, чего, увы, по каким-то прчинам не происходит... Как отлаживать такие алгоритмы (работающие на битовом уровне) я не знаю. Неужели нужно отслеживать каждый нолик или единицу??? smile а может я неправильно применила какую-нибудь побитовую операцию (^, |, &)???

далее моя реализация 1)DES и 2)ГОСТ.

Код

// kurs_test_des_1_(e).cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>

using namespace std;

typedef unsigned long long UINT_64;
typedef unsigned long UINT_32;

template <class T>
T MakePermutation (T block, const int * perm, int perm_sz)
{
        T Res = 0;
        for (int i = 0; i < perm_sz; i++)
        {
                Res |= ((block >> perm[i]) & 1) << i;
        }
        return Res;
}


const int IP[64] =  {6,    14,    22,    30,    38,    46,    54,    62,
                     4,    12,    20,    28,    36,    44,    52,    60,
                     2,    10,    18,    26,    34,    42,    50,    58,
                     0,    8,    16,    24,    32,    40,    48,    56,
                     7,    15,    23,    31,    39,    47,    55,    63,
                     5, 13,    21,    29,    37,    45,    53,    61,
                     3,    11,    19,    27,    35,    43,    51,    59,
                     1, 9,    17,    25,    33,    41,    49,    57};
/*{57, 49, 41, 33, 25, 17, 9, 1,
                    59, 51, 43, 35, 27, 19, 11, 3,
                    61, 53, 45, 37, 29, 21, 13, 5,
                    63, 55, 47, 39, 31, 23, 15, 7,
                    56, 48, 40, 32, 24, 16, 8,  0,
                    58, 50, 42, 34, 26, 18, 10, 2,
                    60, 52, 44, 36, 28, 20, 12, 4,
                    62, 54, 46, 38, 30, 22, 14, 6};*/

const int IP_rev[64] =    {24, 56, 16, 48, 8,    40,    0,    32,
                         25, 57, 17, 49, 9, 41, 1,  33,
                         26, 58, 18, 50, 10, 42, 2, 34,
                         27, 59, 19, 51, 11, 43, 3, 35,
                         28, 60, 20, 52, 12, 44, 4,    36,
                         29, 61, 21, 53, 13, 45, 5, 37,
                         30, 62, 22, 54, 14, 46, 6, 38,
                         31, 63, 23, 55, 15, 47, 7, 39};

/*{39, 7, 47, 15, 55, 23, 63, 31,
                        38, 6, 46, 14, 54, 22, 62, 30,
                        37, 5, 45, 13, 53, 21, 61, 29,
                        36, 4, 44, 12, 52, 20, 60, 28,
                        35, 3, 43, 11, 51, 19, 59, 27,
                        34, 2, 42, 10, 50, 18, 58, 26,
                        33, 1, 41, 9,  49, 17, 57, 25,
                        32, 0, 40, 8,  48, 16, 56, 24 };*/

const int E[48] =    {0,    31,    30,    29,    28,    27,
                    28,    27,    26,    25,    24,    23,
                    24,    23,    22,    21,    20,    19,
                    20,    19,    18,    17,    16,    15,
                    16,    15,    14,    13,    12,    11,
                    12,    11,    10,    9,    8,    7,
                    8,    7,    6,    5,    4,    3,
                    4,    3,    2,    1,    0,    31};

/*{31, 0,  1,  2,  3,  4,
                   3,  4,  5,  6,  7,  8,
                   7,  8,  9,  10, 11, 12,
                   11, 12, 13, 14, 15, 16,
                   15, 16, 17, 18, 19, 20,
                   19, 20, 21, 22, 23, 24,
                   23, 24, 25, 26, 27, 28,
                   27, 28, 29, 30, 31, 0  };*/


const UINT_32 S[8][4][16] =
{{{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7},
  {0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8},
  {4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0},
  {15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13}},
 {{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10},
  {3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5},
  {0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15},
  {13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9}},
 {{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8},
  {13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1},
  {13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7},
  {1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12}},
 {{7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15},
  {13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9},
  {10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4},
  {3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14}},
 {{2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9},
  {14, 11, 2, 12, 4, 7,    13, 1, 5, 0, 15, 10, 3, 9, 8, 6},
  {4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14},
  {11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3}},
 {{12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11},
  {10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8},
  {9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6},
  {4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13}},
 {{4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1},
  {13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6},
  {1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2},
  {6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12}},
 {{13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7},
  {1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2},
  {7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8},
  {2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11}}
};

const int P[32] =    {16, 25, 12, 11, 3,    20, 4, 15,
                     31, 17, 9,    6,    27, 14,    1, 22,
                     30, 24, 8, 18, 0,  5, 29, 23,
                     13, 19, 2, 26, 10, 21,    28, 7};
/*{15, 26, 19, 20, 28, 11, 27, 16,
                   0,  14, 22, 25, 4,  17, 30, 9,
                   1,  7,  23, 13, 31, 26, 2,  8,
                   18, 12, 29, 5,  21, 10, 3, 26};*/


const int CP1[56] = 
                    {7,    15,    23,    31,    39,    47,    55,
                    63,    6,    14,    22,    30,    38,    46,
                    54,    62,    5,    13,    21,    29,    37,
                    45,    53,    61,    4,    12,    20,    28,
                    1,    9,    17,    25,    33,    41,    49,
                    57,    2,    10,    18,    26,    34,    42,
                    50,    58,    3,    11,    19,    27,    35,
                    43,    51,    59,    36,    44,    52,    60};
/*{56, 48, 40, 32, 24, 16, 8,
                     0,  57, 49, 41, 33, 25, 17,
                     9,  1,  58, 50, 42, 34, 26,
                     18, 10, 2,  59, 51, 43, 35,
                     62, 54, 46, 38, 30, 22, 14,
                     6,  61, 53, 45, 37, 29, 21,
                     13, 45, 60, 52, 42, 36, 28,
                     20, 12, 24, 27, 19, 11, 3}; */

const int CP2[56] = 
                    {42, 39, 45, 32, 55, 51,
                    53,    28,    41,    50,    35,    46,
                    33,    37,    44,    52,    30,    48,
                    40,    49,    29,    36,    43,    54,
                    15,    4,    25,    19,    9,    1,
                    26,    16,    5,    11,    23,    8,
                    12,    7,    17,    0,    22,    3,
                    10,    14,    6,    20,    27,    24};
/*{13, 16, 10, 23, 0, 4,
                     2,  27, 14, 5,  20, 9,
                     22, 18, 11, 3,  25, 7,
                     14, 5,  25, 18, 11, 0,
                     40, 51, 30, 36, 46, 54,
                     29, 39, 50, 46, 32, 47,
                     43, 48, 38, 55, 33, 52,
                     45, 41, 49, 35, 28, 31};   */
const int R[16] = {1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};

UINT_64 *  make_keys(UINT_64 key)
{
        UINT_64 r_key[16];
        MakePermutation<UINT_64> (key, CP1, 56);
        UINT_32 low = key << 4;
        UINT_32 hi = key >> 36;
        UINT_32 C, D;
        C = hi; D = low;
        for (int i = 0; i < 16; i++)
        {
               C << R[i];
               D << R[i];
               r_key[i] = (UINT_64(hi) << 32) | UINT_64(low);
               MakePermutation<UINT_64>(r_key[i], CP2, 56);
        }
        return r_key;
}


UINT_32 RoundEncrypt(UINT_32 b, UINT_64 key)
{
        UINT_64 bb = MakePermutation<UINT_64> (b, E, 48) ^ key;
        UINT_32 bits6, row, col, val, Res;
        Res = 0;
        for (int i = 0; i < 8; i++)
        {
                bits6 = bb >> (6*(7-i)) & 31; //111111 (2)
                row = ((bits6 >> 5) << 1) | (bits6 & 1);
                col = (bits6 >> 1) & 15; // 1111 (2)
                val = S[i][row][col];
                Res |= val << (4*(7-i));
        }
        return MakePermutation<UINT_32> (Res, P, 32);
}



UINT_64 des_encrypt(UINT_64 block, UINT_64 Key)
{
        UINT_64 * round_key = new UINT_64[16];
        round_key =  make_keys(Key); //!!!!!!!!!!!
        block = MakePermutation<UINT_64>(block, IP, 64);
        UINT_32 low_prev = block;
        UINT_32 hi_prev = block >> 32;
        UINT_32 low, hi;
        for (int i = 0; i < 16; i++)
        {
                hi = low_prev;
                low = hi_prev ^ RoundEncrypt(low_prev, round_key[i]);
                hi_prev = hi;
                low_prev = low;
        }
        UINT_64 res = (UINT_64(hi) << 32) | UINT_64(low);
        return MakePermutation<UINT_64>(res, IP_rev, 64);
}
//**********************************************************************

UINT_64 des_decrypt(UINT_64 block, UINT_64 Key)
{
        UINT_64 * round_key = new UINT_64[16];
        round_key =  make_keys(Key); //!!!!!!!!!!!
        block = MakePermutation<UINT_64>(block, IP, 64);
        UINT_32 low_prev = block;
        UINT_32 hi_prev = block >> 32;
        UINT_32 low, hi;
        for (int i = 16; i > 0; i--)
        {
                hi = low_prev;
                low = hi_prev ^ RoundEncrypt(low_prev, round_key[i]);
                hi_prev = hi;
                low_prev = low;
        }
        UINT_64 res = (UINT_64(hi) << 32) | UINT_64(low);
        return MakePermutation<UINT_64>(res, IP_rev, 64);
}


//**********************************************************************
int _tmain(int argc, _TCHAR* argv[])
{
    UINT_64 BLOCK(12345678912345678912), KEY(654846774845), REZULT(0), REZULT1(0);
    cout << BLOCK << endl << KEY << endl;
    REZULT = des_encrypt(BLOCK, KEY);
    cout << REZULT << endl;
    REZULT1 = des_decrypt(REZULT, KEY);
    cout << REZULT1 << endl;
        
    return 0;
}





Код


// kurs_test_gost_1_(e).cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>

using namespace std;

typedef unsigned long long UINT_64;
typedef unsigned long UINT_32;

template <class T>
T MakePermutation (T block, const int * perm, int perm_sz)
{
        T Res = 0;
        for (int i = 0; i < perm_sz; i++)
        {
                Res |= ((block >> perm[i]) & 1) << i;
        }
        return Res;
}

const UINT_32 S[8][16] = {{4, 10, 9, 2, 13, 8, 0, 14, 6, 11, 1, 12, 7, 15, 5, 3},
                          {14, 11, 4, 12, 6, 13, 15, 10, 2, 3, 8, 1, 0, 7, 5, 9},
                          {5, 8, 1, 13, 10, 3, 4, 2, 14, 15, 12, 7, 6, 0, 9, 11},
                          {7, 13, 10, 1, 0, 8, 9, 15, 14, 4, 6, 12, 11, 2, 5, 3},
                          {6, 12, 7, 1, 5, 15, 13, 8, 4, 10, 9, 14,    0, 3, 11, 2},
                          {4, 11, 10, 0, 7, 2, 1, 13, 3, 6, 8, 5, 9, 12, 15, 14},
                          {13, 11, 4, 1, 3, 15,    5, 9, 0, 10, 14, 7, 6, 8, 2, 12},
                          {1, 15, 13, 0, 5, 7, 10, 4, 9, 2, 3, 14, 6, 11, 8, 12}}; 


UINT_32 RoundEncrypt(UINT_32 b, UINT_32 k)
{
    b = UINT_32((UINT_64(b) + (UINT_64(k)) % (UINT_64(1) << 32)));
    UINT_32 bits4, row, col, res, val;
    res = 0;
    for (int i = 0; i < 8; i++)
    {
        bits4 = b >> (4*(7-i)) & 15;
        row = i;
        col = bits4;
        val = S[row][col];
        res |= val << (4*(7-i));
    }
    return res;
}



UINT_64 gost_encrypt(UINT_64 block, UINT_32 * round_key)
{
    UINT_32 low_prev = block;
    UINT_32 hi_prev = block >> 32;
    UINT_32 hi, low;
    for (int i = 1; i <= 32; i++)
    {
        hi = low_prev;
        if (i <= 32) low = hi ^ RoundEncrypt(low_prev, round_key[(i-1)%8]);
        else
            if (i <= 31) low = hi ^ RoundEncrypt(low_prev, round_key[32-i]);
            else
                if (i == 32) low = hi ^ RoundEncrypt(low_prev, round_key[0]);
        hi_prev = hi;
        low_prev = low;
    }
    UINT_64 res = (UINT_64(hi) << 32)| (UINT_64(low));
    return (res << 11);
}
//**********************************************************************

UINT_64 gost_decrypt(UINT_64 block, UINT_32 * round_key)
{
    UINT_32 low_prev = block;
    UINT_32 hi_prev = block >> 32;
    UINT_32 hi, low;
    for (int i = 1; i <= 8; i++)
    {
        hi = low_prev;
        if (i <= 32) low = hi ^ RoundEncrypt(low_prev, round_key[(i-1)%8]);
        else
            if (i <= 31) low = hi ^ RoundEncrypt(low_prev, round_key[32-i]);
            else
                if (i == 32) low = hi ^ RoundEncrypt(low_prev, round_key[0]);
        hi_prev = hi;
        low_prev = low;
    }
    
    for (int i = 32; i >= 1; i--)
    {
        hi = low_prev;
        if (i <= 32) low = hi ^ RoundEncrypt(low_prev, round_key[(i-1)%8]);
        else
            if (i <= 31) low = hi ^ RoundEncrypt(low_prev, round_key[32-i]);
            else
                if (i == 32) low = hi ^ RoundEncrypt(low_prev, round_key[0]);
        hi_prev = hi;
        low_prev = low;
    }
    UINT_64 res = (UINT_64(hi) << 32)| (UINT_64(low));
    return (res << 11);
}


//**********************************************************************
int _tmain(int argc, _TCHAR* argv[])
{
    UINT_64 BLOCK(11111111111111111111), REZULT(0), REZULT1(0);
    UINT_32 * KEY = new UINT_32[8];
    for (int i = 0; i < 8; i++) KEY[i] = UINT_32(i*i);
    cout << BLOCK << endl;
    for (int i = 0; i < 8; i++) cout << KEY[i] << " ";
    cout << endl;
    REZULT = gost_encrypt(BLOCK, KEY);
    cout << REZULT << endl;
    REZULT1 = gost_decrypt(REZULT, KEY);
    cout << REZULT1 << endl;
        
    return 0;
}




через 3 дня мне ее уже сдавать... smile 
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Центр помощи"

ВНИМАНИЕ! Прежде чем создавать темы, или писать сообщения в данный раздел, ознакомьтесь, пожалуйста, с Правилами форума и конкретно этого раздела.
Несоблюдение правил может повлечь за собой самые строгие меры от закрытия/удаления темы до бана пользователя!


  • Название темы должно отражать её суть! (Не следует добавлять туда слова "помогите", "срочно" и т.п.)
  • При создании темы, первым делом в квадратных скобках укажите область, из которой исходит вопрос (язык, дисциплина, диплом). Пример: [C++].
  • В названии темы не нужно указывать происхождение задачи (например "школьная задача", "задача из учебника" и т.п.), не нужно указывать ее сложность ("простая задача", "легкий вопрос" и т.п.). Все это можно писать в тексте самой задачи.
  • Если Вы ошиблись при вводе названия темы, отправьте письмо любому из модераторов раздела (через личные сообщения или report).
  • Для подсветки кода пользуйтесь тегами [code][/code] (выделяйте код и нажимаете на кнопку "Код"). Не забывайте выбирать при этом соответствующий язык.
  • Помните: один топик - один вопрос!
  • В данном разделе запрещено поднимать темы, т.е. при отсутствии ответов на Ваш вопрос добавлять новые ответы к теме, тем самым поднимая тему на верх списка.
  • Если вы хотите, чтобы вашу проблему решили при помощи определенного алгоритма, то не забудьте описать его!
  • Если вопрос решён, то воспользуйтесь ссылкой "Пометить как решённый", которая находится под кнопками создания темы или специальным флажком при ответе.

Более подробно с правилами данного раздела Вы можете ознакомится в этой теме.

Если Вам помогли и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, Poseidon, Rodman

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Центр помощи | Следующая тема »


 




[ Время генерации скрипта: 0.0893 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.