Ключ для защиты от копирования.

1. Назначение и краткое описание схемы.

Описываемая здесь схема предназначена для защиты программ от нелегального копирования. Ее использование позволяет практически полностью исключить эту возможность, так как часть защищаемой программы можно хранить в микроконтроллере, с установленым битом защиты, не позволяющим ее считать, а значит и скопировать. Ключ подключается к параллельному порту и может работать одновременно с принтером. Сразу замечу, что эта схема имеет два ограничения. Во-первых программа микроконтроллера ничего не делает кроме получения данных от компьютера, их хранения и отправки обратно. Этого достаточно чтобы программно определить наличие или отсутствие ключа, но если в микроконтроллер записать часть программы или перед возвращением данных их шифровать, степень защиты значительно увеличится. Я думаю границей между двумя этими вариантами является цена защищаемой программы в несколько сотен долларов. И во-вторых эта схема не всегда позволяет работать принтеру подключенному к тому же порту. Epson Stylus Color 600 прекрасно работал, и даже автоматически определился, а Epson LX 1050+ нет. Для исправления этого надо будет немного переделать схему. Но и этот вариант можно использовать с некоторыми принтерами или, если принтер нужен и он не работает, использовать переключатель порта DataSwitch. Если принтер не подключен схема устойчиво работает.

2. Схема.

3. Комментарии к схеме.

В целях уменьшения размера и стоимости устройства использован микроконтроллер 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.

4. Программа микроконтроллера.


.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

5. Программа РС.

Исходник на С примера проверяющго наличие ключа.

#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(); // Отключение питания ключа

}

Автор: Сафонников Валентин

Назад