Описываемая здесь схема предназначена для защиты программ от нелегального копирования. Ее использование позволяет практически полностью исключить эту возможность, так как часть защищаемой программы можно хранить в микроконтроллере, с установленым битом защиты, не позволяющим ее считать, а значит и скопировать. Ключ подключается к параллельному порту и может работать одновременно с принтером. Сразу замечу, что эта схема имеет два ограничения. Во-первых программа микроконтроллера ничего не делает кроме получения данных от компьютера, их хранения и отправки обратно. Этого достаточно чтобы программно определить наличие или отсутствие ключа, но если в микроконтроллер записать часть программы или перед возвращением данных их шифровать, степень защиты значительно увеличится. Я думаю границей между двумя этими вариантами является цена защищаемой программы в несколько сотен долларов. И во-вторых эта схема не всегда позволяет работать принтеру подключенному к тому же порту. Epson Stylus Color 600 прекрасно работал, и даже автоматически определился, а Epson LX 1050+ нет. Для исправления этого надо будет немного переделать схему. Но и этот вариант можно использовать с некоторыми принтерами или, если принтер нужен и он не работает, использовать переключатель порта DataSwitch. Если принтер не подключен схема устойчиво работает.
В целях уменьшения размера и стоимости устройства использован микроконтроллер AT90S1200 с внутренним RC генератором. Это позволяет спокойно разместить всю собраную схему внутри разъема или переходника подключеного к порту, а стоимость не превышает примерно 100 рублей. Для обмена данными применяется синхронный последовательный интерфейс, назначение линий приведено в таблице.
Вывод микроконтроллера |
Вывод порта |
Назначение сигнала |
PORTD.3 | SlctIn | Выбор принтера или ключа |
VSS,RESET | D0..D7 | Питание ключа |
PORTD.0 | Strobe | Данные от компьютера |
PORTD.1 | Busy | Данные от ключа |
PORTD.2 | AutoLF | Импульсы синхронизации от компьютера |
Питание берется с того же порта, при работающем принтере микросхема почти всегда находится в режиме Power Down и потребляет меньше 1 мА, для ее питания достаточно единицы на одном из выводов шины данных. В активном режиме на выводы данных должны быть программно выставлены единицы благодаря чему обеспечиваетя ток достаточный для питания микроконтроллера. Желательно использовать германиевые диоды, т.к. падение напряжения на них меньше. Есть два исполнения микросхемы AT90S1200 с максимальными частотами 4 или 12 МГц и минимальными напряжениями питания соответственно 2,7 и 4 В. Лучше применять первое так как из за существующего разброса параметров паралельных портов на разных компьютерах может оказатся что на питание микросхемы будет подано напряжение менее 4 вольт. Например AT90S1200A-4PC.
.INCLUDE "1200def.inc" ; AT90S1200 @ 1 MHz .CSEG .DEF Byte=r16 .DEF LoopCounter=r18 .DEF Byte0=r19 .DEF Byte1=r20 .DEF Byte2=r21 .DEF Byte3=r22 .DEF Byte4=r23 .DEF Byte5=r24 .DEF Byte6=r25 .DEF Byte7=r26 .ORG 000 rjmp RESET ; Reset Handler .ORG 001 rjmp EXT_INT0 ; IRQ0 Handler RESET: ; Настраиваем направление работы портов. ; Все линии портов после сброса настроены на работу в качестве входов, ; а на неиспользуемых включены pull-up резисторы. cli ldi r31,0 out DDRB,r31 out DDRD,r31 ldi r31,$ff out PORTB,r31 ldi r31,$72 out PORTD,r31 ; Ждем прихода импульса на вход INT0 находясь в режиме Power Down. ldi r31,$40 out GIMSK,r31 ldi r31,$30 out MCUCR,r31 UnLoop: sei sleep rjmp UnLoop EXT_INT0: ; Если PD3=0, данные относятся к принтеру. sbis PIND,3 reti ; Включение ключа. ldi r31,$02 out DDRD,r31 ldi Byte0,$31 ldi Byte1,$32 ldi Byte2,$33 ldi Byte3,$34 ldi Byte4,$35 ldi Byte5,$36 ldi Byte6,$37 ldi Byte7,$38 MainLoop: rcall Byte8Exchange ; Здесь должен быть код заменяющий часть защищаемой программы или ; шифрование данных. sbis PIND,3 rjmp RESET ; работа с ключем завершена, переполнение стека допустимо rjmp MainLoop Byte8Exchange: mov Byte,Byte0 rcall ByteExchange mov Byte0,Byte mov Byte,Byte1 rcall ByteExchange mov Byte1,Byte mov Byte,Byte2 rcall ByteExchange mov Byte2,Byte mov Byte,Byte3 rcall ByteExchange mov Byte3,Byte mov Byte,Byte4 rcall ByteExchange mov Byte4,Byte mov Byte,Byte5 rcall ByteExchange mov Byte5,Byte mov Byte,Byte6 rcall ByteExchange mov Byte6,Byte mov Byte,Byte7 rcall ByteExchange mov Byte7,Byte ret ByteExchange: ;Обмен одним байтом данных. ldi LoopCounter,8 ; Обработка положительного фронта сигнала синхронизации. Loop8: sbrs Byte,7 ; вывод бита cbi PORTD,1 sbrc Byte,7 sbi PORTD,1 Wait1: sbis PIND,2 ; ждем прихода положительного фронта rjmp Wait1 sec ;c=1 ; прием бита sbis PIND,0 clc ;c=0 rol Byte Wait0: sbic PIND,2 ; ждем прихода отрицательного фронта rjmp Wait0 ; Цикл для 8 бит байта. dec LoopCounter brne Loop8 ret .EXIT
Исходник на С примера проверяющго наличие ключа.
#include <dos.h>#include <conio.h>
#include <stdio.h>
char SendByte(char ByteOut)
int i,j;
long li;
unsigned char ByteOutCpy, ByteIn = 0;
ByteOutCpy = ByteOut;
for (i=0; i<8; i++)
{ ByteIn="(ByteIn" << 1) + ((inportb(0x379)&0x80)="=0);
" outportb(0x37A,0x02|(((128&ByteOutCpy)="=0)));
" for (li="0;
" li<2000l; li++);
outportb(0x37A,0x00|(((128&ByteOutCpy)="=0)));
" for (li="0;" li<2000l; li++);
outportb(0x37A,0x02|(((128&ByteOutCpy)="=0)));
" ByteOutCpy="ByteOutCpy" << 1; for (li="0;
" li<2000l; li++); } return ByteIn;
}
void KeyOn(void)
{ int i; long li; for (i="0;" i<64; i++)
{
outportb(0x37A,0x00);
for (li="0;" li<20000l; li++);
outportb(0x37A,0x03);
for (li="0;" li<20000l; li++);
}
delay(100); } void KeyOff(void)
{
int i; long li;
for (i="0;" i<128; i++)
{
outportb(0x37A,0x0B); for (li="0;" li<2000l; li++);
outportb(0x37A,0x08); for (li="0;" li<2000l; li++);
}
}
void main() { KeyOn();
// Включение ключа. printf("%02X ",SendByte(0));
// Отправка 8 байт. printf("%02X ",SendByte(1));
printf("%02X ",SendByte(2));
printf("%02X ",SendByte(3));
printf("%02X ",SendByte(4));
printf("%02X ",SendByte(5));
printf("%02X ",SendByte(6));
printf("%02X ",SendByte(7));
printf("\n"); printf("%02X ",SendByte(7));
// Отправка следующих 8 байт и одновременное printf("%02X ",SendByte(6));
// получение байт отправленых раньше. printf("%02X ",SendByte(5));
printf("%02X ",SendByte(4));
printf("%02X ",SendByte(3));
printf("%02X ",SendByte(2));
printf("%02X ",SendByte(1));
printf("%02X ",SendByte(0));
printf("\n"); printf("%02X ",SendByte(0xF0));
// Отправка следующих 8 байт и одновременное printf("%02X ",SendByte(0xF1));
// получение байт отправленых раньше. printf("%02X ",SendByte(0xF2));
printf("%02X ",SendByte(0xF3));
printf("%02X ",SendByte(0xF4));
printf("%02X ",SendByte(0xF5));
printf("%02X ",SendByte(0xF6));
printf("%02X ",SendByte(0xF7));
printf("\n"); printf("\n");
KeyOff(); // Отключение питания ключа
}
Автор: Сафонников Валентин