REM     The Standart GNU Personal Data Encryption Utility.
REM     Copyright (C) Sandul Yura Valentinovich.
REM     (R) Wednesday, 5 March 2003 year.
REM     This program is free software; you can redistribute it and/or modify
REM it under the terms of the GNU General Public License as published by the
REM Free Software Foundation; either version 2 of the License, or (at your
REM option) any later version.
REM     This program is distributed in the hope that it will be useful, but
REM WITHOUT ANY WARRANTY; without even the implied warranty of
REM MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
REM Public License for more details.
REM     You should have received a copy of the GNU General Public License
REM along with this program; if not, write to the Free Software Foundation,
REM Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
REM
REM     DES is basically a monoalphabetic substitution cipher using a 64 bit
REM character. It has 19 distinct stages. The decryption can be done with the
REM same password, the stages must then be carried out in reverse order.
REM The ciphertext corresponding to the plaintext of 64 zeros and a key of 64
REM zeros is: 8CA64DE9C1B123A7 (hexadecimal) (a password with 8 zero bytes is
REM the default password).
REM                     IMPORTANT NOTES FOR DECRYPTION
REM     Note that random characters are added to the inputfile to make the
REM last block of 64 bits complete, how this problem is generally solved is
REM unclear, the decryption algorithm must take into account any such non
REM standard additions to create a usable encryption or decryption scheme.
REM     With lenght known the random characters possibly added can simply be
REM neglected. WARNING: US federal regulations prevent non US governement
REM users from using the DES algorithm.
REM
REM $DYNAMIC
DECLARE SUB ScratchScreen ()
DECLARE SUB OutBox (Title$, Message$)
DECLARE SUB MakeBox (BoxColumn%, BoxRow%, BoxWidth%, BoxHeight%)
DECLARE SUB SecondsToDateAndTime (SecondsCount#, HourValue%, MinuteValue%, SecondValue%, DayValue%, MonthValue%, YearValue%, DayOfWeekValue%)
DECLARE SUB BitsToString (Bits%(), OutLine$)
DECLARE SUB Compute (Index%, DESData%(), InData%(), OutData%())
DECLARE SUB LetBe (Target%(), Source%(), Last%)
DECLARE SUB Transpose (DESData%(), Work%(), Count%)
DECLARE SUB Rotate (WorkKeyData%())
DECLARE SUB StringToBits (InLine$, Bits%())
DECLARE SUB UnCompute (Index%, DESData%(), InData%(), OutData%())
DECLARE SUB UnRotate (WorkKeyData%())
DECLARE FUNCTION DateAndTimeToSeconds# (HourValue%, MinuteValue%, SecondValue%, DayValue%, MonthValue%, YearValue%)
DECLARE FUNCTION DayName$ (DayNumber%)
DECLARE FUNCTION DayOfWeek% (DayValue%, MonthValue%, YearValue%)
DECLARE FUNCTION DayOfWeekName$ (DayValue%, MonthValue%, YearValue%)
DECLARE FUNCTION DaysCount& (DayValue%, MonthValue%, YearValue%)
DECLARE FUNCTION InputBox% (Title$, Message$, InputTextLine$)
DECLARE FUNCTION IsLeapYear% (YearValue%)
DECLARE FUNCTION MenuBox% (ItemsCount%)
DECLARE FUNCTION MessageBox% (Title$, Message$)
DECLARE FUNCTION MonthDays% (MonthValue%, YearValue%)
DECLARE FUNCTION MonthDaysCount% (MonthValue%, YearValue%)
DECLARE FUNCTION MonthName$ (MonthNumber%)
DECLARE FUNCTION Answer% (Question$)
DECLARE FUNCTION Bin$ (Number%)
DECLARE FUNCTION DESWork$ (InLine$, PasswordLine$)
DECLARE FUNCTION PasswordInputBox% (Title$, Message$, InputTextLine$)
DECLARE FUNCTION UnDESWork$ (InLine$, PasswordLine$)
OPTION BASE 1
CONST False% = 0
CONST True% = NOT False%
DIM SHARED Work%(8, 64)
DIM SHARED BeginData%(64)
DIM SHARED EndData%(64)
DIM SHARED KeyData%(56)
DIM SHARED SwapData%(64)
DIM SHARED CryptWork%(48)
DIM SHARED Enumerated%(48)
DIM SHARED Pointers%(32)
DIM SHARED Rots%(16)
DIM SHARED PlainText%(64)
DIM SHARED HyperText%(64)
DIM SHARED RotateData%(56)
DIM SHARED ComputeData%(64)
DIM SHARED CryptData%(64)
DIM SHARED WorkCryptData%(64)
DIM SHARED InDESData%(64)
DIM SHARED OutDESData%(64)
DIM SHARED WorkDESData%(64)
DIM SHARED Password%(64)
DIM SHARED MenuItems$(8)
DIM Index%
DIM SubIndex%
DIM SourceFileName$
DIM TargetFileName$
DIM PasswordLine$
DIM WorkLine$
DIM RandomText$
DIM Header$
DIM StartDate$
DIM StartTime$
DIM CurrentDate$
DIM CurrentTime$
DIM Index&
DIM WorkValue&
DIM WorkHourValue%
DIM WorkMinuteValue%
DIM WorkSecondValue%
DIM WorkDayValue%
DIM WorkMonthValue%
DIM WorkYearValue%
DIM WorkDayOfWeekValue%
DIM OriginalFileName$
DIM OriginalFileSize&
DIM OriginalDateTime$
DIM Text$
DIM OldSecond%
DIM OldFilePosition&
DIM WorkData$
DIM Description$
DIM UserBreak%
DIM WorkYear%
DIM WorkMonth%
DIM WorkDay%
DIM WorkHour%
DIM WorkMinute%
DIM WorkSecond%
DIM KeysCount&
DIM OldKeysCount&
DIM KeyPasswordData%(9)
DIM KeyLine$
DIM HexKeyLine$
RESTORE BeginData
FOR Index% = 1 TO 64
 READ BeginData%(Index%)
NEXT Index%
RESTORE EndData
FOR Index% = 1 TO 64
 READ EndData%(Index%)
NEXT Index%
RESTORE SwapData
FOR Index% = 1 TO 64
 READ SwapData%(Index%)
NEXT Index%
RESTORE KeyData
FOR Index% = 1 TO 56
 READ KeyData%(Index%)
NEXT Index%
RESTORE CryptWork
FOR Index% = 1 TO 48
 READ CryptWork%(Index%)
NEXT Index%
RESTORE Enumerated
FOR Index% = 1 TO 48
 READ Enumerated%(Index%)
NEXT Index%
RESTORE Pointers
FOR Index% = 1 TO 32
 READ Pointers%(Index%)
NEXT Index%
RESTORE Rots
FOR Index% = 1 TO 16
 READ Rots%(Index%)
NEXT Index%
RESTORE DESBoxes
FOR Index% = 1 TO 8
 FOR SubIndex% = 1 TO 64
  READ Work%(Index%, SubIndex%)
 NEXT SubIndex%
NEXT Index%
PasswordLine$ = "Password"
SourceFileName$ = "File.dat"
TargetFileName$ = "File.des"
DO
 CALL ScratchScreen
 MenuItems$(1) = "Change source file name (" + SourceFileName$ + ".)."
 MenuItems$(2) = "Change target file name (" + TargetFileName$ + ".)."
 MenuItems$(3) = "Change password."
 MenuItems$(4) = "Change description."
 MenuItems$(5) = "Encrypt source file to target."
 MenuItems$(6) = "Decrypt source file to target."
 MenuItems$(7) = "Crack password for source file."
 MenuItems$(8) = "Quit."
 SELECT CASE MenuBox%(8)
 CASE 0
   EXIT DO
 CASE 1
   CALL ScratchScreen
   WorkLine$ = ""
   IF InputBox%("DESUtility.", "Please enter exist file name as source file name.", WorkLine$) THEN
    CALL ScratchScreen
    WorkLine$ = UCASE$(LEFT$(LTRIM$(RTRIM$(WorkLine$)), 1)) + LCASE$(MID$(LTRIM$(RTRIM$(WorkLine$)), 2))
    IF (WorkLine$ = "") OR (LEN(WorkLine$) > 12) OR (INSTR(WorkLine$, ":") > 0) OR (INSTR(WorkLine$, "/") > 0) OR (INSTR(WorkLine$, "\") > 0) OR (INSTR(WorkLine$, "?") > 0) OR (INSTR(WorkLine$, "*") > 0) THEN CALL OutBox("DESUtility.", "You input the invalid file name.") ELSE SourceFileName$ = WorkLine$
   END IF
 CASE 2
   CALL ScratchScreen
   WorkLine$ = ""
   IF InputBox%("DESUtility.", "Please enter target file name.", WorkLine$) THEN
    CALL ScratchScreen
    WorkLine$ = UCASE$(LEFT$(LTRIM$(RTRIM$(WorkLine$)), 1)) + LCASE$(MID$(LTRIM$(RTRIM$(WorkLine$)), 2))
    IF (WorkLine$ = "") OR (LEN(WorkLine$) > 12) OR (INSTR(WorkLine$, ":") > 0) OR (INSTR(WorkLine$, "/") > 0) OR (INSTR(WorkLine$, "\") > 0) OR (INSTR(WorkLine$, "?") > 0) OR (INSTR(WorkLine$, "*") > 0) THEN CALL OutBox("DESUtility.", "You input the invalid file name.") ELSE TargetFileName$ = WorkLine$
   END IF
 CASE 3
   CALL ScratchScreen
   WorkLine$ = ""
   IF PasswordInputBox%("DESUtility.", "Please enter password.", WorkLine$) THEN
    CALL ScratchScreen
    IF (WorkLine$ = "") OR (LEN(WorkLine$) > 8) THEN CALL OutBox("DESUtility.", "You input the invalid password. Password length must be from 1 to 8 symbols.") ELSE PasswordLine$ = WorkLine$ + STRING$(8 - LEN(WorkLine$), CHR$(0))
   END IF
 CASE 4
   CALL ScratchScreen
   WorkLine$ = ""
   IF InputBox%("DESUtility.", "Please enter description for DES file. Length of description may be from 0 to 64 symbols.", WorkLine$) THEN
    CALL ScratchScreen
    IF (WorkLine$ = "") OR (LEN(WorkLine$) > 64) THEN CALL OutBox("DESUtility.", "You input the invalid description.") ELSE Description$ = WorkLine$
   END IF
 CASE 5
   CALL ScratchScreen
   ON ERROR GOTO ErrorOpenSourceFile
   OPEN SourceFileName$ FOR BINARY AS #1
   ON ERROR GOTO ErrorOpenTargetFile
   OPEN TargetFileName$ FOR OUTPUT AS #2
   ON ERROR GOTO 0
   RandomText$ = ""
   FOR Index% = 1 TO 12
    RANDOMIZE TIMER
    RandomText$ = RandomText$ + CHR$(128 + INT(127 * RND(1)))
   NEXT Index%
   StartDate$ = DATE$
   StartTime$ = TIME$
   OldSecond% = NOT VAL(MID$(StartTime$, 7, 2))
   OldFilePosition& = 0
   UserBreak% = False%
   Header$ = "DES" + RandomText$ + MKL$(LOF(1)) + MKI$(((VAL(MID$(StartDate$, 7, 4)) - 1980) * 372) + ((VAL(MID$(StartDate$, 1, 2)) - 1) * 31) + (VAL(MID$(StartDate$, 4, 2)) - 1)) + MKL$((VAL(LEFT$(StartTime$, 2)) * 3600) + (VAL(MID$(StartTime$, 4, 2)) * 60) + VAL(MID$(StartTime$, 7, 2))) + CHR$(LEN(SourceFileName$)) + SourceFileName$ + CHR$(LEN(Description$)) + Description$
   Header$ = Header$ + SPACE$(128 - LEN(Header$))
   WHILE Header$ <> ""
    ON ERROR GOTO CannotPreWriteToTargetFileForEncrypt
    PRINT #2, DESWork$(LEFT$(Header$, 8), PasswordLine$);
    ON ERROR GOTO 0
    Header$ = MID$(Header$, 9)
   WEND
   GOSUB OutEncryptStatusBox
   FOR Index& = 1 TO INT(LOF(1) / 8)
    GOSUB OutEncryptStatus
    IF INKEY$ = CHR$(27) THEN
     UserBreak% = True%
     EXIT FOR
    END IF
    ON ERROR GOTO CannotReadFromSourceFileForEncrypt
    WorkLine$ = INPUT$(8, #1)
    ON ERROR GOTO CannotWriteToTargetFileForEncrypt
    PRINT #2, DESWork$(WorkLine$, PasswordLine$);
    ON ERROR GOTO 0
   NEXT Index&
   IF UserBreak% THEN
    CLOSE #1
    CLOSE #2
    KILL TargetFileName$
    CALL ScratchScreen
    CALL OutBox("DESUtility.", "User break.")
   ELSE
    IF (LOF(1) MOD 8) > 0 THEN
     ON ERROR GOTO CannotReadFromSourceFileForEncrypt
     Text$ = INPUT$(LOF(1) MOD 8, #1) + LEFT$(RandomText$, 8 - (LOF(1) MOD 8))
     ON ERROR GOTO CannotWriteToTargetFileForEncrypt
     PRINT #2, DESWork$(Text$, PasswordLine$);
     ON ERROR GOTO 0
    END IF
    CLOSE #1
    CLOSE #2
    CALL ScratchScreen
    CALL OutBox("DESUtility.", "Source file is succefully encrypted to target file.")
   END IF
 CASE 6
   CALL ScratchScreen
   ON ERROR GOTO ErrorOpenSourceFile
   OPEN SourceFileName$ FOR BINARY AS #1
   ON ERROR GOTO ErrorOpenTargetFile
   OPEN TargetFileName$ FOR OUTPUT AS #2
   ON ERROR GOTO CannotPreReadFromSourceFileForDecrypt
   Header$ = INPUT$(128, #1)
   ON ERROR GOTO 0
   IF NOT (LEFT$(UnDESWork$(LEFT$(Header$, 8), PasswordLine$), 3) = "DES") THEN
    CLOSE #1
    CLOSE #2
    KILL TargetFileName$
    CALL OutBox("DESUtility.", "Invalid password.")
   ELSE
    WorkLine$ = ""
    WHILE Header$ <> ""
     WorkLine$ = WorkLine$ + UnDESWork$(LEFT$(Header$, 8), PasswordLine$)
     Header$ = MID$(Header$, 9)
    WEND
    Header$ = MID$(WorkLine$, 4)
    RandomText$ = LEFT$(Header$, 12)
    Header$ = MID$(Header$, 13)
    OriginalFileSize& = CVL(LEFT$(Header$, 4))
    Header$ = MID$(Header$, 5)
    WorkValue& = CVI(LEFT$(Header$, 2))
    Header$ = MID$(Header$, 3)
    WorkYear% = INT(WorkValue& / 372) + 1980
    WorkValue& = WorkValue& - ((WorkYear% - 1980) * 372)
    WorkMonth% = INT(WorkValue& / 31) + 1
    WorkDay% = (WorkValue& - ((WorkMonth% - 1) * 31)) + 1
    WorkValue& = CVL(LEFT$(Header$, 4))
    Header$ = MID$(Header$, 5)
    WorkHour% = INT(WorkValue& / 3600)
    WorkValue& = WorkValue& - (WorkHour% * 3600&)
    WorkMinute% = INT(WorkValue& / 60)
    WorkSecond% = WorkValue& - (WorkMinute% * 60)
    OriginalDateTime$ = DayOfWeekName$(WorkDay%, WorkMonth%, WorkYear%) + ", " + LTRIM$(STR$(WorkDay%)) + " " + MonthName$(WorkMonth%) + " " + LTRIM$(STR$(WorkYear%)) + " year. Time: " + STRING$(2 - LEN(LTRIM$(STR$(WorkHour%))), "0") + LTRIM$(STR$(WorkHour%)) + ":" + STRING$(2 - LEN(LTRIM$(STR$(WorkMinute%))), "0") + LTRIM$(STR$(WorkMinute%)) + ":" + STRING$(2 - LEN(LTRIM$(STR$(WorkSecond%))), "0") + LTRIM$(STR$(WorkSecond%))
    OriginalFileName$ = MID$(Header$, 2, ASC(Header$))
    Header$ = MID$(Header$, ASC(Header$) + 2)
    Description$ = MID$(Header$, 2, ASC(Header$))
    StartDate$ = DATE$
    StartTime$ = TIME$
    OldSecond% = NOT VAL(MID$(StartTime$, 7, 2))
    OldFilePosition& = 0
    UserBreak% = False%
    GOSUB OutDecryptStatusBox
    FOR Index& = 1 TO (INT(LOF(1) / 8) - 16) - 1
     GOSUB OutDecryptStatus
     IF INKEY$ = CHR$(27) THEN
      UserBreak% = True%
      EXIT FOR
     END IF
     ON ERROR GOTO CannotReadFromSourceFileForEncrypt
     WorkLine$ = INPUT$(8, #1)
     ON ERROR GOTO CannotWriteToTargetFileForEncrypt
     PRINT #2, UnDESWork$(WorkLine$, PasswordLine$);
     ON ERROR GOTO 0
    NEXT Index&
    IF UserBreak% THEN
     CLOSE #1
     CLOSE #2
     KILL TargetFileName$
     CALL ScratchScreen
     CALL OutBox("DESUtility.", "User break.")
    ELSE
     ON ERROR GOTO CannotReadFromSourceFileForEncrypt
     Text$ = INPUT$(8, #1)
     ON ERROR GOTO 0
     Text$ = UnDESWork$(Text$, PasswordLine$)
     Text$ = LEFT$(Text$, (OriginalFileSize& + 136) - LOF(1))
     IF Text$ <> "" THEN
      ON ERROR GOTO CannotWriteToTargetFileForEncrypt
      PRINT #2, Text$;
      ON ERROR GOTO 0
     END IF
     IF (LOF(1) MOD 8) > 0 THEN
      ON ERROR GOTO CannotReadFromSourceFileForEncrypt
      Text$ = INPUT$(LOF(1) MOD 8, #1) + LEFT$(RandomText$, 8 - (LOF(1) MOD 8))
      ON ERROR GOTO CannotWriteToTargetFileForEncrypt
      PRINT #2, LEFT$(UnDESWork$(Text$, PasswordLine$), LOF(1) MOD 8);
      ON ERROR GOTO 0
     END IF
     CLOSE #1
     CLOSE #2
     CALL ScratchScreen
     CALL OutBox("DESUtility.", "Source file is succefully decrypted to target file.")
    END IF
   END IF
 CASE 7
   CALL ScratchScreen
   ON ERROR GOTO ErrorOpenSourceFile
   OPEN SourceFileName$ FOR BINARY AS #1
   ON ERROR GOTO CannotReadFromSourceFileForCrack
   WorkData$ = INPUT$(8, #1)
   ON ERROR GOTO 0
   CLOSE #1
   StartDate$ = DATE$
   StartTime$ = TIME$
   OldSecond% = NOT VAL(MID$(StartTime$, 7, 2))
   KeysCount& = 0
   OldKeysCount& = 0
   UserBreak% = False%
   FOR Index% = 1 TO 9
    KeyPasswordData%(Index%) = 0
   NEXT Index%
   GOSUB OutCrackStatusBox
   DO
    IF INKEY$ = CHR$(27) THEN
     UserBreak% = True%
     EXIT DO
    END IF
    IF KeysCount& = 2147483647 THEN
     CALL ScratchScreen
     CALL OutBox("DESUtility.", "Password is not found.")
     EXIT DO
    END IF
    KeysCount& = KeysCount& + 1
    KeyLine$ = ""
    Index% = 1
    WHILE KeyPasswordData%(Index%) = 255
     KeyPasswordData%(Index%) = 0
     Index% = Index% + 1
    WEND
    DO
     IF KeyPasswordData%(Index%) = 255 THEN
      KeyPasswordData%(Index%) = 0
      Index% = Index% + 1
     END IF
     KeyPasswordData%(Index%) = KeyPasswordData%(Index%) + 1
    LOOP UNTIL KeyPasswordData%(Index%) < 256
    FOR Index% = 1 TO 8
     IF KeyPasswordData%(Index%) > (ASC(SPACE$(1)) - 1) THEN KeyLine$ = KeyLine$ + CHR$(KeyPasswordData%(Index%)) ELSE EXIT FOR
    NEXT Index%
    HexKeyLine$ = ""
    FOR Index% = 1 TO 8
     IF LEN(HEX$(KeyPasswordData%(Index%))) < 2 THEN HexKeyLine$ = HexKeyLine$ + "0" + HEX$(KeyPasswordData%(Index%)) ELSE HexKeyLine$ = HexKeyLine$ + HEX$(KeyPasswordData%(Index%))
    NEXT Index%
    PasswordLine$ = KeyLine$ + STRING$(8 - LEN(KeyLine$), CHR$(0))
    IF LEFT$(UnDESWork$(WorkData$, PasswordLine$), 3) = "DES" THEN
     CALL ScratchScreen
     CALL OutBox("DESUtility.", "Password is found.")
     EXIT DO
    END IF
    GOSUB OutCrackStatus
   LOOP UNTIL HexKeyLine$ = STRING$(16, "FF")
   CALL ScratchScreen
   IF UserBreak% = True% THEN CALL OutBox("DESUtility.", "User break.")
 CASE 8
   EXIT DO
 END SELECT
WorkRepeat:
LOOP
COLOR 7, 0
CLS
LOCATE 1, 1, 1, 7, 8
END
OutEncryptStatusBox:
 CALL MakeBox(1, 6, 77, 12)
 PRINT "Encryption." + SPACE$(66);
 COLOR 1, 7
 LOCATE 8, 2, 0
 PRINT "    Source file name: ";
 COLOR 4, 7
 PRINT SourceFileName$;
 COLOR 1, 7
 PRINT ".";
 LOCATE 9, 2, 0
 PRINT "    Target file name: ";
 COLOR 4, 7
 PRINT TargetFileName$;
 COLOR 1, 7
 PRINT ".";
 LOCATE 10, 2, 0
 PRINT "    Source file size: ";
 COLOR 4, 7
 PRINT SPACE$(10 - LEN(LTRIM$(STR$(LOF(1))))) + LTRIM$(STR$(LOF(1)));
 COLOR 1, 7
 PRINT " bytes.";
 LOCATE 11, 2, 0
 PRINT "    Target file size: " + SPACE$(10) + " bytes.";
 LOCATE 12, 2, 0
 PRINT "Source file position: " + SPACE$(10) + ".";
 LOCATE 13, 2, 0
 PRINT "    Conversion speed: " + SPACE$(10) + " bytes per second.";
 LOCATE 14, 2, 0
 PRINT "   % Completed.";
 LOCATE 15, 2, 0
 PRINT "  Start time: ";
 COLOR 4, 7
 PRINT "Date: " + DayOfWeekName$(VAL(MID$(StartDate$, 4, 2)), VAL(MID$(StartDate$, 1, 2)), VAL(MID$(StartDate$, 7, 4))) + ", " + LTRIM$(STR$(VAL(MID$(StartDate$, 4, 2)))) + " " + MonthName$(VAL(MID$(StartDate$, 1, 2))) + " " + LTRIM$(STR$(VAL(MID$(StartDate$, 7, 4)))) + " year. Time: " + StartTime$;
 COLOR 1, 7
 PRINT ".";
 LOCATE 16, 2, 0
 PRINT "Current time:";
 LOCATE 17, 2, 0
 PRINT "   Past time:";
 COLOR 14, 7
 LOCATE 18, 2, 0
 PRINT "[ESC]=Break.";
 RETURN
OutEncryptStatus:
 COLOR 4, 7
 LOCATE 11, 24, 0
 PRINT SPACE$(10 - LEN(LTRIM$(STR$(LOF(2))))) + LTRIM$(STR$(LOF(2)));
 LOCATE 12, 24, 0
 PRINT SPACE$(10 - LEN(LTRIM$(STR$(LOC(1))))) + LTRIM$(STR$(LOC(1)));
 LOCATE 14, 2, 0
 PRINT STRING$(3 - LEN(LTRIM$(STR$(INT((LOC(1) * 100) / LOF(1))))), "0") + LTRIM$(STR$(INT((LOC(1) * 100) / LOF(1))));
 CurrentDate$ = DATE$
 CurrentTime$ = TIME$
 IF VAL(MID$(CurrentTime$, 7, 2)) <> OldSecond% THEN
  OldSecond% = VAL(MID$(CurrentTime$, 7, 2))
  LOCATE 13, 24, 0
  PRINT SPACE$(10 - LEN(LTRIM$(STR$(LOC(1) - OldFilePosition&)))) + LTRIM$(STR$(LOC(1) - OldFilePosition&));
  OldFilePosition& = LOC(1)
  LOCATE 16, 16, 0
  PRINT SPACE$(63);
  LOCATE 16, 16, 0
  PRINT "Date: " + DayOfWeekName$(VAL(MID$(CurrentDate$, 4, 2)), VAL(MID$(CurrentDate$, 1, 2)), VAL(MID$(CurrentDate$, 7, 4))) + ", " + LTRIM$(STR$(VAL(MID$(CurrentDate$, 4, 2)))) + " " + MonthName$(VAL(MID$(CurrentDate$, 1, 2))) + " " + LTRIM$(STR$(VAL(MID$(CurrentDate$, 7, 4)))) + " year. Time: " + CurrentTime$;
  COLOR 1, 7
  PRINT ".";
  CALL SecondsToDateAndTime(DateAndTimeToSeconds#(VAL(MID$(CurrentTime$, 1, 2)), VAL(MID$(CurrentTime$, 4, 2)), VAL(MID$(CurrentTime$, 7, 2)), VAL(MID$(CurrentDate$, 4, 2)), VAL(MID$(CurrentDate$, 1, 2)), VAL(MID$(CurrentDate$, 7, 4))) - DateAndTimeToSeconds#(VAL(MID$(StartTime$, 1, 2)), VAL(MID$(StartTime$, 4, 2)), VAL(MID$(StartTime$, 7, 2)), VAL(MID$(StartDate$, 4, 2)), VAL(MID$(StartDate$, 1, 2)), VAL(MID$(StartDate$, 7, 4))), WorkHourValue%, WorkMinuteValue%, WorkSecondValue%, WorkDayValue%, WorkMonthValue%, WorkYearValue%, WorkDayOfWeekValue%)
  COLOR 4, 7
  LOCATE 17, 16, 0
  PRINT SPACE$(63);
  LOCATE 17, 16, 0
  PRINT "Date: " + DayName$(WorkDayOfWeekValue%) + ", " + LTRIM$(STR$(WorkDayValue%)) + " " + MonthName$(WorkMonthValue%) + " " + LTRIM$(STR$(WorkYearValue%)) + " year. Time: " + STRING$(2 - LEN(LTRIM$(STR$(WorkHourValue%))), "0") + LTRIM$(STR$(WorkHourValue%)) + ":" + STRING$(2 - LEN(LTRIM$(STR$(WorkMinuteValue%))), "0") + LTRIM$(STR$(WorkMinuteValue%)) + ":" + STRING$(2 - LEN(LTRIM$(STR$(WorkSecondValue%))), "0") + LTRIM$(STR$(WorkSecondValue%));
  COLOR 1, 7
  PRINT ".";
 END IF
 RETURN
OutDecryptStatusBox:
 CALL MakeBox(1, 3, 77, 17)
 PRINT "Decryption." + SPACE$(66);
 COLOR 1, 7
 LOCATE 5, 2, 0
 PRINT "Original file name: ";
 COLOR 4, 7
 PRINT OriginalFileName$;
 COLOR 1, 7
 PRINT ".";
 LOCATE 6, 2, 0
 PRINT "Original file size: ";
 COLOR 4, 7
 PRINT SPACE$(10 - LEN(LTRIM$(STR$(OriginalFileSize&)))) + LTRIM$(STR$(OriginalFileSize&));
 COLOR 1, 7
 PRINT " bytes.";
 LOCATE 7, 2, 0
 PRINT "Original file date/time: ";
 COLOR 4, 7
 LOCATE 8, 2, 0
 PRINT OriginalDateTime$;
 COLOR 1, 7
 PRINT ".";
 LOCATE 9, 2, 0
 PRINT "Description: ";
 COLOR 4, 7
 PRINT Description$;
 COLOR 1, 7
 PRINT ".";
 LOCATE 10, 2, 0
 PRINT "    Source file name: ";
 COLOR 4, 7
 PRINT SourceFileName$;
 COLOR 1, 7
 PRINT ".";
 LOCATE 11, 2, 0
 PRINT "    Target file name: ";
 COLOR 4, 7
 PRINT TargetFileName$;
 COLOR 1, 7
 PRINT ".";
 LOCATE 12, 2, 0
 PRINT "    Source file size: ";
 COLOR 4, 7
 PRINT SPACE$(10 - LEN(LTRIM$(STR$(LOF(1))))) + LTRIM$(STR$(LOF(1)));
 COLOR 1, 7
 PRINT " bytes.";
 LOCATE 13, 2, 0
 PRINT "    Target file size: " + SPACE$(10) + " bytes.";
 LOCATE 14, 2, 0
 PRINT "Source file position: " + SPACE$(10) + ".";
 LOCATE 15, 2, 0
 PRINT "    Conversion speed: " + SPACE$(10) + " bytes per second.";
 LOCATE 16, 2, 0
 PRINT "   % Completed.";
 LOCATE 17, 2, 0
 PRINT "  Start time: ";
 COLOR 4, 7
 PRINT "Date: " + DayOfWeekName$(VAL(MID$(StartDate$, 4, 2)), VAL(MID$(StartDate$, 1, 2)), VAL(MID$(StartDate$, 7, 4))) + ", " + LTRIM$(STR$(VAL(MID$(StartDate$, 4, 2)))) + " " + MonthName$(VAL(MID$(StartDate$, 1, 2))) + " " + LTRIM$(STR$(VAL(MID$(StartDate$, 7, 4)))) + " year. Time: " + StartTime$;
 COLOR 1, 7
 PRINT ".";
 LOCATE 18, 2, 0
 PRINT "Current time:";
 LOCATE 19, 2, 0
 PRINT "   Past time:";
 COLOR 14, 7
 LOCATE 20, 2, 0
 PRINT "[ESC]=Break.";
 RETURN
OutDecryptStatus:
 COLOR 4, 7
 LOCATE 13, 24, 0
 PRINT SPACE$(10 - LEN(LTRIM$(STR$(LOF(2))))) + LTRIM$(STR$(LOF(2)));
 LOCATE 14, 24, 0
 PRINT SPACE$(10 - LEN(LTRIM$(STR$(LOC(1))))) + LTRIM$(STR$(LOC(1)));
 LOCATE 16, 2, 0
 PRINT STRING$(3 - LEN(LTRIM$(STR$(INT((LOC(1) * 100) / LOF(1))))), "0") + LTRIM$(STR$(INT((LOC(1) * 100) / LOF(1))));
 CurrentDate$ = DATE$
 CurrentTime$ = TIME$
 IF VAL(MID$(CurrentTime$, 7, 2)) <> OldSecond% THEN
  OldSecond% = VAL(MID$(CurrentTime$, 7, 2))
  LOCATE 15, 24, 0
  PRINT SPACE$(10 - LEN(LTRIM$(STR$(LOC(1) - OldFilePosition&)))) + LTRIM$(STR$(LOC(1) - OldFilePosition&));
  OldFilePosition& = LOC(1)
  LOCATE 18, 16, 0
  PRINT SPACE$(63);
  LOCATE 18, 16, 0
  PRINT "Date: " + DayOfWeekName$(VAL(MID$(CurrentDate$, 4, 2)), VAL(MID$(CurrentDate$, 1, 2)), VAL(MID$(CurrentDate$, 7, 4))) + ", " + LTRIM$(STR$(VAL(MID$(CurrentDate$, 4, 2)))) + " " + MonthName$(VAL(MID$(CurrentDate$, 1, 2))) + " " + LTRIM$(STR$(VAL(MID$(CurrentDate$, 7, 4)))) + " year. Time: " + CurrentTime$;
  COLOR 1, 7
  PRINT ".";
  CALL SecondsToDateAndTime(DateAndTimeToSeconds#(VAL(MID$(CurrentTime$, 1, 2)), VAL(MID$(CurrentTime$, 4, 2)), VAL(MID$(CurrentTime$, 7, 2)), VAL(MID$(CurrentDate$, 4, 2)), VAL(MID$(CurrentDate$, 1, 2)), VAL(MID$(CurrentDate$, 7, 4))) - DateAndTimeToSeconds#(VAL(MID$(StartTime$, 1, 2)), VAL(MID$(StartTime$, 4, 2)), VAL(MID$(StartTime$, 7, 2)), VAL(MID$(StartDate$, 4, 2)), VAL(MID$(StartDate$, 1, 2)), VAL(MID$(StartDate$, 7, 4))), WorkHourValue%, WorkMinuteValue%, WorkSecondValue%, WorkDayValue%, WorkMonthValue%, WorkYearValue%, WorkDayOfWeekValue%)
  COLOR 4, 7
  LOCATE 19, 16, 0
  PRINT SPACE$(63);
  LOCATE 19, 16, 0
  PRINT "Date: " + DayName$(WorkDayOfWeekValue%) + ", " + LTRIM$(STR$(WorkDayValue%)) + " " + MonthName$(WorkMonthValue%) + " " + LTRIM$(STR$(WorkYearValue%)) + " year. Time: " + STRING$(2 - LEN(LTRIM$(STR$(WorkHourValue%))), "0") + LTRIM$(STR$(WorkHourValue%)) + ":" + STRING$(2 - LEN(LTRIM$(STR$(WorkMinuteValue%))), "0") + LTRIM$(STR$(WorkMinuteValue%)) + ":" + STRING$(2 - LEN(LTRIM$(STR$(WorkSecondValue%))), "0") + LTRIM$(STR$(WorkSecondValue%));
  COLOR 1, 7
  PRINT ".";
 END IF
 RETURN
OutCrackStatusBox:
 CALL MakeBox(1, 5, 77, 14)
 PRINT "Crack password." + SPACE$(62);
 COLOR 1, 7
 LOCATE 7, 2, 0
 PRINT "            Source file name: ";
 COLOR 4, 7
 PRINT SourceFileName$;
 COLOR 1, 7
 PRINT ".";
 LOCATE 8, 2, 0
 PRINT "             Passwords count: " + SPACE$(10) + ".";
 LOCATE 9, 2, 0
 PRINT "                    Password: `" + SPACE$(8) + "'.";
 LOCATE 10, 2, 0
 PRINT "Password in hexadecimal type: " + SPACE$(16) + ".";
 LOCATE 11, 2, 0
 PRINT "              Cracking speed: " + SPACE$(10) + " passwords per second.";
 LOCATE 12, 2, 0
 PRINT "  Start time: ";
 COLOR 4, 7
 PRINT "Date: " + DayOfWeekName$(VAL(MID$(StartDate$, 4, 2)), VAL(MID$(StartDate$, 1, 2)), VAL(MID$(StartDate$, 7, 4))) + ", " + LTRIM$(STR$(VAL(MID$(StartDate$, 4, 2)))) + " " + MonthName$(VAL(MID$(StartDate$, 1, 2))) + " " + LTRIM$(STR$(VAL(MID$(StartDate$, 7, 4)))) + " year. Time: " + StartTime$;
 COLOR 1, 7
 PRINT ".";
 LOCATE 13, 2, 0
 PRINT "Current time:";
 LOCATE 14, 2, 0
 PRINT "   Past time:";
 LOCATE 15, 2, 0
 PRINT "Before terminating has stay: ";
 LOCATE 17, 2, 0
 PRINT "Note: Password count range for DES algorithm is: 18446744073709551616.";
 LOCATE 18, 2, 0
 PRINT "This utility can crack the only 2147483647 password.";
 COLOR 14, 7
 LOCATE 19, 2, 0
 PRINT "[ESC]=Break.";
 RETURN
OutCrackStatus:
 COLOR 4, 7
 LOCATE 8, 32, 0
 PRINT SPACE$(10 - LEN(LTRIM$(STR$(KeysCount&)))) + LTRIM$(STR$(KeysCount&));
 LOCATE 9, 33, 0
 PRINT KeyLine$ + SPACE$(8 - LEN(KeyLine$));
 LOCATE 10, 32, 0
 PRINT HexKeyLine$;
 CurrentDate$ = DATE$
 CurrentTime$ = TIME$
 IF VAL(MID$(CurrentTime$, 7, 2)) <> OldSecond% THEN
  OldSecond% = VAL(MID$(CurrentTime$, 7, 2))
  LOCATE 11, 32, 0
  PRINT SPACE$(10 - LEN(LTRIM$(STR$(KeysCount& - OldKeysCount&)))) + LTRIM$(STR$(KeysCount& - OldKeysCount&));
  LOCATE 13, 16, 0
  PRINT SPACE$(63);
  LOCATE 13, 16, 0
  PRINT "Date: " + DayOfWeekName$(VAL(MID$(CurrentDate$, 4, 2)), VAL(MID$(CurrentDate$, 1, 2)), VAL(MID$(CurrentDate$, 7, 4))) + ", " + LTRIM$(STR$(VAL(MID$(CurrentDate$, 4, 2)))) + " " + MonthName$(VAL(MID$(CurrentDate$, 1, 2))) + " " + LTRIM$(STR$(VAL(MID$(CurrentDate$, 7, 4)))) + " year. Time: " + CurrentTime$;
  COLOR 1, 7
  PRINT ".";
  CALL SecondsToDateAndTime(DateAndTimeToSeconds#(VAL(MID$(CurrentTime$, 1, 2)), VAL(MID$(CurrentTime$, 4, 2)), VAL(MID$(CurrentTime$, 7, 2)), VAL(MID$(CurrentDate$, 4, 2)), VAL(MID$(CurrentDate$, 1, 2)), VAL(MID$(CurrentDate$, 7, 4))) - DateAndTimeToSeconds#(VAL(MID$(StartTime$, 1, 2)), VAL(MID$(StartTime$, 4, 2)), VAL(MID$(StartTime$, 7, 2)), VAL(MID$(StartDate$, 4, 2)), VAL(MID$(StartDate$, 1, 2)), VAL(MID$(StartDate$, 7, 4))), WorkHourValue%, WorkMinuteValue%, WorkSecondValue%, WorkDayValue%, WorkMonthValue%, WorkYearValue%, WorkDayOfWeekValue%)
  COLOR 4, 7
  LOCATE 14, 16, 0
  PRINT SPACE$(63);
  LOCATE 14, 16, 0
  PRINT "Date: " + DayName$(WorkDayOfWeekValue%) + ", " + LTRIM$(STR$(WorkDayValue%)) + " " + MonthName$(WorkMonthValue%) + " " + LTRIM$(STR$(WorkYearValue%)) + " year. Time: " + STRING$(2 - LEN(LTRIM$(STR$(WorkHourValue%))), "0") + LTRIM$(STR$(WorkHourValue%)) + ":" + STRING$(2 - LEN(LTRIM$(STR$(WorkMinuteValue%))), "0") + LTRIM$(STR$(WorkMinuteValue%)) + ":" + STRING$(2 - LEN(LTRIM$(STR$(WorkSecondValue%))), "0") + LTRIM$(STR$(WorkSecondValue%));
  COLOR 1, 7
  PRINT ".";
  COLOR 4, 7
  LOCATE 16, 2, 0
  PRINT SPACE$(77);
  LOCATE 16, 2, 0
  IF OldKeysCount& <> 0 THEN CALL SecondsToDateAndTime(DateAndTimeToSeconds#(VAL(MID$(StartTime$, 1, 2)), VAL(MID$(StartTime$, 4, 2)), VAL(MID$(StartTime$, 7, 2)), VAL(MID$(StartDate$, 4, 2)), VAL(MID$(StartDate$, 1, 2)), VAL(MID$(StartDate$, 7, 4))) + INT(2147483647 / (KeysCount& - OldKeysCount&)), WorkHourValue%, WorkMinuteValue%, WorkSecondValue%, WorkDayValue%, WorkMonthValue%, WorkYearValue%, WorkDayOfWeekValue%)
  IF WorkMonthValue% < 1 THEN WorkMonthValue% = 1
  PRINT "Date: " + DayName$(WorkDayOfWeekValue%) + ", " + LTRIM$(STR$(WorkDayValue%)) + " " + MonthName$(WorkMonthValue%) + " " + LTRIM$(STR$(WorkYearValue%)) + " year. Time: " + STRING$(2 - LEN(LTRIM$(STR$(WorkHourValue%))), "0") + LTRIM$(STR$(WorkHourValue%)) + ":" + STRING$(2 - LEN(LTRIM$(STR$(WorkMinuteValue%))), "0") + LTRIM$(STR$(WorkMinuteValue%)) + ":" + STRING$(2 - LEN(LTRIM$(STR$(WorkSecondValue%))), "0") + LTRIM$(STR$(WorkSecondValue%));
  COLOR 1, 7
  PRINT ".";
  OldKeysCount& = KeysCount&
 END IF
 RETURN
ErrorOpenSourceFile:
 IF MessageBox%("DESUtility.", "Cannot open source file. Retry opening?") THEN
  CALL ScratchScreen
  RESUME
 ELSE
  RESUME WorkRepeat
 END IF
ErrorOpenTargetFile:
 IF MessageBox%("DESUtility.", "Cannot open target file. Retry opening?") THEN
  CALL ScratchScreen
  RESUME
 ELSE
  CLOSE #1
  RESUME WorkRepeat
 END IF
CannotReadFromSourceFileForCrack:
 IF MessageBox%("DESUtility.", "Cannot read from the source file. Retry reading?") THEN
  CALL ScratchScreen
  RESUME
 ELSE
  CLOSE #1
  RESUME WorkRepeat
 END IF
CannotPreReadFromSourceFileForDecrypt:
 IF MessageBox%("DESUtility.", "Cannot read from the source file. Retry reading?") THEN
  CALL ScratchScreen
  RESUME
 ELSE
  CLOSE #1
  CLOSE #2
  KILL TargetFileName$
  RESUME WorkRepeat
 END IF
CannotPreWriteToTargetFileForEncrypt:
 IF MessageBox%("DESUtility.", "Cannot write to target file. Retry writing?") THEN
  CALL ScratchScreen
  RESUME
 ELSE
  CLOSE #1
  CLOSE #2
  KILL TargetFileName$
  RESUME WorkRepeat
 END IF
CannotReadFromSourceFileForEncrypt:
 IF MessageBox%("DESUtility.", "Cannot read from source file. Retry reading?") THEN
  CALL ScratchScreen
  GOSUB OutEncryptStatusBox
  GOSUB OutEncryptStatus
  RESUME
 ELSE
  CLOSE #1
  CLOSE #2
  KILL TargetFileName$
  RESUME WorkRepeat
 END IF
CannotWriteToTargetFileForEncrypt:
 IF MessageBox%("DESUtility.", "Cannot write to target file. Retry writing?") THEN
  CALL ScratchScreen
  GOSUB OutEncryptStatusBox
  GOSUB OutEncryptStatus
  RESUME
 ELSE
  CLOSE #1
  CLOSE #2
  KILL TargetFileName$
  RESUME WorkRepeat
 END IF
BeginData:
 DATA 58,50,42,34,26,18,10,02,60,52,44,36,28,20,12,04
 DATA 62,54,46,38,30,22,14,06,64,56,48,40,32,24,16,08
 DATA 57,49,41,33,25,17,09,01,59,51,43,35,27,19,11,03
 DATA 61,53,45,37,29,21,13,05,63,55,47,39,31,23,15,07
EndData:
 DATA 40,08,48,16,56,24,64,32,39,07,47,15,55,23,63,31
 DATA 38,06,46,14,54,22,62,30,37,05,45,13,53,21,61,29
 DATA 36,04,44,12,52,20,60,28,35,03,43,11,51,19,59,27
 DATA 34,02,42,10,50,18,58,26,33,01,41,09,49,17,57,25
SwapData:
 DATA 33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48
 DATA 49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64
 DATA 01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,16
 DATA 17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32
KeyData:
 DATA 57,49,41,33,25,17,09,01,58,50,42,34,26,18
 DATA 10,02,59,51,43,35,27,19,11,03,60,52,44,36
 DATA 63,55,47,39,31,23,15,07,62,54,46,38,30,22
 DATA 14,06,61,53,45,37,29,21,13,05,28,20,12,04
CryptWork:
 DATA 14,17,11,24,01,05,03,28,15,06,21,10
 DATA 23,19,12,04,26,08,16,07,27,20,13,02
 DATA 41,52,31,37,47,55,30,40,51,45,33,48
 DATA 44,49,39,56,34,53,46,42,50,36,29,32
Enumerated:
 DATA 32,01,02,03,04,05,04,05,06,07,08,09
 DATA 08,09,10,11,12,13,12,13,14,15,16,17
 DATA 16,17,18,19,20,21,20,21,22,23,24,25
 DATA 24,25,26,27,28,29,28,29,30,31,32,01
Pointers:
 DATA 16,07,20,21,29,12,28,17,01,15,23,26,05,18,31,10
 DATA 02,08,24,14,32,27,03,09,19,13,30,06,22,11,04,25
DESBoxes:
 DATA 14,04,13,01,02,15,11,08,03,10,06,12,05,09,00,07
 DATA 00,15,07,04,14,02,13,01,10,06,12,11,09,05,03,08
 DATA 04,01,14,08,13,06,02,11,15,12,09,07,03,10,05,00
 DATA 15,12,08,02,04,09,01,07,05,11,03,14,10,00,06,13
 DATA 15,01,08,14,06,11,03,04,09,07,02,13,12,00,05,10
 DATA 03,13,04,07,15,02,08,14,12,00,01,10,06,09,11,05
 DATA 00,14,07,11,10,04,13,01,05,08,12,06,09,03,02,15
 DATA 13,08,10,01,03,15,04,02,11,06,07,12,00,05,14,09
 DATA 10,00,09,14,06,03,15,05,01,13,12,07,11,04,02,08
 DATA 13,07,00,09,03,04,06,10,02,08,05,14,12,11,15,01
 DATA 13,06,04,09,08,15,03,00,11,01,02,12,05,10,14,07
 DATA 01,10,13,00,06,09,08,07,04,15,14,03,11,05,02,12
 DATA 07,13,14,03,00,06,09,10,01,02,08,05,11,12,04,15
 DATA 13,08,11,05,06,15,00,03,04,07,02,12,01,10,14,09
 DATA 10,06,09,00,12,11,07,13,15,01,03,14,05,02,08,04
 DATA 03,15,00,06,10,01,13,08,09,04,05,11,12,07,02,14
 DATA 02,12,04,01,07,10,11,06,08,05,03,15,13,00,14,09
 DATA 14,11,02,12,04,07,13,01,05,00,15,10,03,09,08,06
 DATA 04,02,01,11,10,13,07,08,15,09,12,05,06,03,00,14
 DATA 11,08,12,07,01,14,02,13,06,15,00,09,10,04,05,03
 DATA 12,01,10,15,09,02,06,08,00,13,03,04,14,07,05,11
 DATA 10,15,04,02,07,12,09,05,06,01,13,14,00,11,03,08
 DATA 09,14,15,05,02,08,12,03,07,00,04,10,01,13,11,06
 DATA 04,03,02,12,09,05,15,10,11,14,01,07,06,00,08,13
 DATA 04,11,02,14,15,00,08,13,03,12,09,07,05,10,06,01
 DATA 13,00,11,07,04,09,01,10,14,03,05,12,02,15,08,06
 DATA 01,04,11,13,12,03,07,14,10,15,06,08,00,05,09,02
 DATA 06,11,13,08,01,04,10,07,09,05,00,15,14,02,03,12
 DATA 13,02,08,04,06,15,11,01,10,09,03,14,05,00,12,07
 DATA 01,15,13,08,10,03,07,04,12,05,06,11,00,14,09,02
 DATA 07,11,04,01,09,12,14,02,00,06,10,13,15,03,05,08
 DATA 02,01,14,07,04,10,08,13,15,12,09,00,03,05,06,11
Rots:
 DATA 1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1

FUNCTION Answer% (Question$)
 LOCATE CSRLIN, 1, 0
 PRINT SPACE$(79);
 LOCATE CSRLIN, 1, 1, 7, 8
 PRINT LEFT$(Question$, 72) + "? [Y/N]";
 DO
  SELECT CASE UCASE$(INKEY$)
  CASE "Y"
    Answer% = 1
    EXIT DO
  CASE "N"
    Answer% = 0
    EXIT DO
  END SELECT
 LOOP
 LOCATE CSRLIN, 1, 0
 PRINT SPACE$(79);
 LOCATE CSRLIN, 1, 1, 7, 8
END FUNCTION

FUNCTION Bin$ (Number%)
 DIM Value%
 DIM Index%
 DIM OutNumber$
 OutNumber$ = ""
 Value% = Number%
 FOR Index% = 1 TO 8
  IF (Value% MOD 2) = 1 THEN OutNumber$ = "1" + OutNumber$ ELSE OutNumber$ = "0" + OutNumber$
  Value% = INT(Value% / 2)
 NEXT Index%
 Bin$ = OutNumber$
END FUNCTION

SUB BitsToString (Bits%(), OutLine$)
 DIM Index%
 DIM SubIndex%
 DIM Value%
 OutLine$ = ""
 FOR Index% = 1 TO 8
  Value% = 0
  FOR SubIndex% = 1 TO 8
   Value% = Value% + ((Bits%(((Index% - 1) * 8) + SubIndex%)) * (2 ^ (8 - SubIndex%)))
  NEXT SubIndex%
  OutLine$ = OutLine$ + CHR$(Value%)
 NEXT Index%
END SUB

SUB Compute (Index%, DESData%(), InData%(), OutData%())
 DIM Temp%
 DIM SubIndex%
 DIM WorkIndex%
 DIM WorkData%
 Temp% = Index%
 CALL LetBe(ComputeData%(), InData%(), 64)
 CALL Transpose(ComputeData%(), Enumerated%(), 48)
 FOR SubIndex% = 1 TO Rots%(Temp%)
  CALL Rotate(DESData%())
 NEXT SubIndex%
 CALL LetBe(CryptData%(), DESData%(), 64)
 CALL Transpose(CryptData%(), CryptWork%(), 48)
 FOR SubIndex% = 1 TO 48
  IF (ComputeData%(SubIndex%) + CryptData%(SubIndex%) = 1) THEN WorkCryptData%(SubIndex%) = 1 ELSE WorkCryptData%(SubIndex%) = 0
 NEXT SubIndex%
 FOR WorkIndex% = 1 TO 8
  WorkData% = (32 * WorkCryptData%((6 * WorkIndex%) - 5)) + (16 * WorkCryptData%(6 * WorkIndex%)) + (8 * WorkCryptData%((6 * WorkIndex%) - 4)) + (4 * WorkCryptData%((6 * WorkIndex%) - 3)) + (2 * WorkCryptData%((6 * WorkIndex%) - 2)) + WorkCryptData%((6 * WorkIndex%) - 1) + 1
  IF (INT(Work%(WorkIndex%, WorkData%) / 8) MOD 2) THEN OutData%((4 * WorkIndex%) - 3) = 1 ELSE OutData%((4 * WorkIndex%) - 3) = 0
  IF (INT(Work%(WorkIndex%, WorkData%) / 4) MOD 2) THEN OutData%((4 * WorkIndex%) - 2) = 1 ELSE OutData%((4 * WorkIndex%) - 2) = 0
  IF (INT(Work%(WorkIndex%, WorkData%) / 2) MOD 2) THEN OutData%((4 * WorkIndex%) - 1) = 1 ELSE OutData%((4 * WorkIndex%) - 1) = 0
  IF (Work%(WorkIndex%, WorkData%) MOD 2) THEN OutData%(4 * WorkIndex%) = 1 ELSE OutData%(4 * WorkIndex%) = 0
 NEXT WorkIndex%
 CALL Transpose(OutData%(), Pointers%(), 32)
END SUB

FUNCTION DateAndTimeToSeconds# (HourValue%, MinuteValue%, SecondValue%, DayValue%, MonthValue%, YearValue%)
 DateAndTimeToSeconds# = (YearValue% * (416 * 86400#)) + (MonthValue% * (32 * 86400)) + (DayValue% * 86400) + (HourValue% * 3600!) + (MinuteValue% * 60) + SecondValue%
END FUNCTION

FUNCTION DayName$ (DayNumber%)
 SELECT CASE DayNumber%
 CASE 1
   DayName$ = "Monday"
 CASE 2
   DayName$ = "Tuesday"
 CASE 3
   DayName$ = "Wednesday"
 CASE 4
   DayName$ = "Thursday"
 CASE 5
   DayName$ = "Friday"
 CASE 6
   DayName$ = "Saturday"
 CASE 7
   DayName$ = "Sunday"
 END SELECT
END FUNCTION

FUNCTION DayOfWeek% (DayValue%, MonthValue%, YearValue%)
 SELECT CASE DaysCount&(DayValue%, MonthValue%, YearValue%) - (INT(DaysCount&(DayValue%, MonthValue%, YearValue%) / 7) * 7)
 CASE 0
   DayOfWeek% = 6
 CASE 1
   DayOfWeek% = 7
 CASE 2
   DayOfWeek% = 1
 CASE 3
   DayOfWeek% = 2
 CASE 4
   DayOfWeek% = 3
 CASE 5
   DayOfWeek% = 4
 CASE 6
   DayOfWeek% = 5
 CASE 7
   DayOfWeek% = 6
 END SELECT
END FUNCTION

FUNCTION DayOfWeekName$ (DayValue%, MonthValue%, YearValue%)
 DayOfWeekName$ = DayName$(DayOfWeek%(DayValue%, MonthValue%, YearValue%))
END FUNCTION

FUNCTION DaysCount& (DayValue%, MonthValue%, YearValue%)
 DaysCount& = (YearValue% * 365#) + INT(YearValue% / 100) + INT(YearValue% / 4) + MonthDaysCount%(MonthValue%, YearValue%) + DayValue%
END FUNCTION

FUNCTION DESWork$ (InLine$, PasswordLine$)
 DIM TempLine$
 DIM Index%
 DIM SubIndex%
 TempLine$ = ""
 CALL StringToBits(InLine$, PlainText%())
 CALL StringToBits(PasswordLine$, Password%())
 CALL LetBe(InDESData%(), PlainText%(), 64)
 CALL Transpose(InDESData%(), BeginData%(), 64)
 CALL Transpose(Password%(), KeyData%(), 56)
 FOR Index% = 1 TO 16
  CALL LetBe(OutDESData%(), InDESData%(), 64)
  FOR SubIndex% = 1 TO 32
   InDESData%(SubIndex%) = OutDESData%(SubIndex% + 32)
  NEXT SubIndex%
  CALL Compute(Index%, Password%(), InDESData%(), WorkDESData%())
  FOR SubIndex% = 1 TO 32
   IF (OutDESData%(SubIndex%) + WorkDESData%(SubIndex%) = 1) THEN InDESData%(SubIndex% + 32) = 1 ELSE InDESData%(SubIndex% + 32) = 0
  NEXT SubIndex%
 NEXT Index%
 CALL Transpose(InDESData%(), SwapData%(), 64)
 CALL Transpose(InDESData%(), EndData%(), 64)
 CALL LetBe(HyperText%(), InDESData%(), 64)
 CALL BitsToString(HyperText%(), TempLine$)
 DESWork$ = TempLine$
END FUNCTION

FUNCTION InputBox% (Title$, Message$, InputTextLine$)
 DIM OutMessage$
 DIM OutIndex%
 DIM WorkKey$
 DIM InputTextCursorColumn%
 DIM InputTextCursorPosition%
 DIM InputText$
 IF LEN(Message$) < 256 THEN OutMessage$ = Message$ + SPACE$(256 - LEN(Message$)) ELSE OutMessage$ = LEFT$(Message$, 256)
 CALL MakeBox(7, 8, 64, 7)
 PRINT LEFT$(Title$, 64) + SPACE$(64 - LEN(LEFT$(Title$, 64)));
 COLOR 1, 7
 FOR OutIndex% = 1 TO 4
  LOCATE 9 + OutIndex%, 8, 0
  PRINT LEFT$(OutMessage$, 64);
  OutMessage$ = MID$(OutMessage$, 65)
 NEXT OutIndex%
 COLOR 14, 7
 LOCATE 15, 8, 0
 PRINT "Please press key is equalient to your answer: ENTER=Yes, ESC=No.";
 InputTextCursorColumn% = 1
 InputTextCursorPosition% = 1
 InputText$ = InputTextLine$
 GOSUB OutInputLine
 DO
  WorkKey$ = INKEY$
  SELECT CASE LEN(WorkKey$)
  CASE 1
    SELECT CASE WorkKey$
    CASE CHR$(8)
      IF InputTextCursorColumn% > 1 THEN
       InputTextCursorColumn% = InputTextCursorColumn% - 1
       InputTextCursorPosition% = InputTextCursorPosition% - 1
       IF InputTextCursorColumn% < 1 THEN InputTextCursorColumn% = 1
       IF InputTextCursorPosition% < 1 THEN InputTextCursorPosition% = 1
       InputText$ = MID$(InputText$, 1, InputTextCursorColumn% - 1) + MID$(InputText$, InputTextCursorColumn% + 1)
       GOSUB OutInputLine
      END IF
    CASE CHR$(13)
      InputTextLine$ = InputText$
      EXIT DO
    CASE CHR$(27)
      EXIT DO
    CASE ELSE
      IF (LEN(InputText$) < 256) AND (ASC(WorkKey$) > (ASC(SPACE$(1)) - 1)) THEN
       InputText$ = MID$(InputText$, 1, InputTextCursorColumn% - 1) + WorkKey$ + MID$(InputText$, InputTextCursorColumn%)
       InputTextCursorColumn% = InputTextCursorColumn% + 1
       InputTextCursorPosition% = InputTextCursorPosition% + 1
       IF InputTextCursorColumn% > LEN(InputText$) + 1 THEN InputTextCursorColumn% = LEN(InputText$) + 1
       IF LEN(InputText$) > 63 THEN IF InputTextCursorPosition% > 64 THEN InputTextCursorPosition% = 64
       IF LEN(InputText$) < 65 THEN IF InputTextCursorPosition% > LEN(InputText$) + 1 THEN InputTextCursorPosition% = LEN(InputText$) + 1
       GOSUB OutInputLine
      END IF
    END SELECT
  CASE 2
    WorkKey$ = MID$(WorkKey$, 2)
    SELECT CASE WorkKey$
    CASE CHR$(75)
      IF InputTextCursorColumn% > 1 THEN
       InputTextCursorColumn% = InputTextCursorColumn% - 1
       InputTextCursorPosition% = InputTextCursorPosition% - 1
       IF InputTextCursorColumn% < 1 THEN InputTextCursorColumn% = 1
       IF InputTextCursorPosition% < 1 THEN InputTextCursorPosition% = 1
       GOSUB OutInputLine
      END IF
    CASE CHR$(77)
      IF InputTextCursorColumn% < LEN(InputText$) + 1 THEN
       InputTextCursorColumn% = InputTextCursorColumn% + 1
       InputTextCursorPosition% = InputTextCursorPosition% + 1
       IF InputTextCursorColumn% > LEN(InputText$) + 1 THEN InputTextCursorColumn% = LEN(InputText$) + 1
       IF LEN(InputText$) > 63 THEN IF InputTextCursorPosition% > 64 THEN InputTextCursorPosition% = 64
       IF LEN(InputText$) < 65 THEN IF InputTextCursorPosition% > LEN(InputText$) + 1 THEN InputTextCursorPosition% = LEN(InputText$) + 1
       GOSUB OutInputLine
      END IF
    CASE CHR$(71)
      IF InputTextCursorColumn% <> 1 THEN
       InputTextCursorColumn% = 1
       InputTextCursorPosition% = 1
       GOSUB OutInputLine
      END IF
    CASE CHR$(79)
      IF InputTextCursorColumn% <> LEN(InputText$) + 1 THEN
       InputTextCursorColumn% = LEN(InputText$) + 1
       InputTextCursorPosition% = LEN(InputText$) + 1
       IF LEN(InputText$) > 63 THEN IF InputTextCursorPosition% > 64 THEN InputTextCursorPosition% = 64
       IF LEN(InputText$) < 65 THEN IF InputTextCursorPosition% > LEN(InputText$) + 1 THEN InputTextCursorPosition% = LEN(InputText$) + 1
       GOSUB OutInputLine
      END IF
    CASE CHR$(83)
      IF InputText$ <> "" THEN
       InputText$ = MID$(InputText$, 1, InputTextCursorColumn% - 1) + MID$(InputText$, InputTextCursorColumn% + 1)
       GOSUB OutInputLine
      END IF
    END SELECT
  END SELECT
 LOOP
 LOCATE , , 0
 InputBox% = WorkKey$ = CHR$(13)
 EXIT FUNCTION
OutInputLine:
 COLOR 4, 7
 LOCATE 14, 8, 0
 PRINT MID$(InputText$, (InputTextCursorColumn% - InputTextCursorPosition%) + 1, 64) + SPACE$(64 - LEN(MID$(InputText$, (InputTextCursorColumn% - InputTextCursorPosition%) + 1, 64)));
 LOCATE 14, 7 + InputTextCursorPosition%, 1, 7, 8
 RETURN
END FUNCTION

FUNCTION IsLeapYear% (YearValue%)
 IsLeapYear% = ABS((INT(YearValue% / 4) * 4) = YearValue%)
END FUNCTION

SUB LetBe (Target%(), Source%(), Last%)
 DIM Index%
 FOR Index% = 1 TO Last%
  Target%(Index%) = Source%(Index%)
 NEXT Index%
END SUB

SUB MakeBox (BoxColumn%, BoxRow%, BoxWidth%, BoxHeight%)
 DIM BoxWorkIndex%
 IF (BoxColumn% < 1) OR (BoxRow% < 1) OR (BoxWidth% < 1) OR (BoxHeight% < 1) OR (BoxWidth% > 77) OR (BoxHeight% > 22) OR (((BoxColumn% - 1) + BoxWidth%) > 77) OR (((BoxRow% - 1) + BoxHeight%) > 22) THEN EXIT SUB
 COLOR 0, 7
 LOCATE BoxRow%, BoxColumn%, 0
 PRINT CHR$(201) + STRING$(BoxWidth%, CHR$(205)) + CHR$(187);
 FOR BoxWorkIndex% = 1 TO BoxHeight% + 1
  LOCATE BoxRow% + BoxWorkIndex%, BoxColumn%, 0
  PRINT CHR$(186) + SPACE$(BoxWidth%) + CHR$(186);
  COLOR 0, 0
  PRINT SPACE$(1);
  COLOR 0, 7
 NEXT BoxWorkIndex%
 LOCATE BoxRow% + BoxHeight% + 1, BoxColumn%, 0
 PRINT CHR$(200) + STRING$(BoxWidth%, CHR$(205)) + CHR$(188);
 COLOR 0, 0
 LOCATE BoxRow% + BoxHeight% + 2, BoxColumn% + 1, 0
 PRINT SPACE$(BoxWidth% + 2);
 COLOR 15, 2
 LOCATE BoxRow% + 1, BoxColumn% + 1, 0
END SUB

FUNCTION MenuBox% (ItemsCount%)
 DIM MenuIndex%
 DIM MenuLineLength%
 DIM CurrentItem%
 DIM WorkKey$
 IF (ItemsCount% < 1) OR (ItemsCount% > UBOUND(MenuItems$)) OR (UBOUND(MenuItems$) > 20) THEN
  MenuBox% = 0
  EXIT FUNCTION
 END IF
 MenuLineLength% = 0
 FOR MenuIndex% = 1 TO ItemsCount%
  IF LEN(MenuItems$(MenuIndex%)) > MenuLineLength% THEN MenuLineLength% = LEN(MenuItems$(MenuIndex%))
 NEXT MenuIndex%
 IF MenuLineLength% < 56 THEN MenuLineLength% = 56
 IF MenuLineLength% > 75 THEN MenuLineLength% = 75
 CurrentItem% = 1
 GOSUB OutMenu
 DO
  WorkKey$ = UCASE$(INKEY$)
  SELECT CASE LEN(WorkKey$)
  CASE 1
    SELECT CASE WorkKey$
    CASE CHR$(13)
      MenuBox% = CurrentItem%
      EXIT DO
    CASE CHR$(27)
      MenuBox% = 0
      EXIT DO
    CASE ELSE
      IF (ASC(WorkKey$) > (ASC("A") - 1)) AND (ASC(WorkKey$) < (ASC("A") + ItemsCount%)) THEN
       CurrentItem% = (ASC(WorkKey$) - ASC("A")) + 1
       GOSUB OutMenu
      END IF
    END SELECT
  CASE 2
    WorkKey$ = MID$(WorkKey$, 2)
    SELECT CASE WorkKey$
    CASE CHR$(72)
      IF CurrentItem% > 1 THEN
       CurrentItem% = CurrentItem% - 1
       GOSUB OutMenu
      END IF
    CASE CHR$(80)
      IF CurrentItem% < ItemsCount% THEN
       CurrentItem% = CurrentItem% + 1
       GOSUB OutMenu
      END IF
    CASE CHR$(73)
      IF CurrentItem% <> 1 THEN
       CurrentItem% = 1
       GOSUB OutMenu
      END IF
    CASE CHR$(81)
      IF CurrentItem% <> ItemsCount% THEN
       CurrentItem% = ItemsCount%
       GOSUB OutMenu
      END IF
    CASE CHR$(71)
      IF CurrentItem% <> 1 THEN
       CurrentItem% = 1
       GOSUB OutMenu
      END IF
    CASE CHR$(79)
      IF CurrentItem% <> ItemsCount% THEN
       CurrentItem% = ItemsCount%
       GOSUB OutMenu
      END IF
    END SELECT
  END SELECT
 LOOP
 EXIT FUNCTION
OutMenu:
 CALL MakeBox(INT((80 - (MenuLineLength% + 5)) / 2) + 1, INT((25 - (ItemsCount% + 5)) / 2) + 1, MenuLineLength% + 2, ItemsCount% + 2)
 FOR MenuIndex% = 1 TO ItemsCount%
  COLOR 14, 7
  LOCATE INT((25 - (ItemsCount% + 5)) / 2) + (MenuIndex% + 1), INT((80 - (MenuLineLength% + 5)) / 2) + 2, 0
  PRINT CHR$(ASC("A") + (MenuIndex% - 1));
  COLOR 12, 7
  PRINT "=";
  IF MenuIndex% = CurrentItem% THEN COLOR 15, 6 ELSE COLOR 8, 7
  PRINT LEFT$(MenuItems$(MenuIndex%), MenuLineLength%) + SPACE$(MenuLineLength% - LEN(LEFT$(MenuItems$(MenuIndex%), MenuLineLength%)));
 NEXT MenuIndex%
 COLOR 0, 7
 LOCATE INT((25 - (ItemsCount% + 5)) / 2) + 2 + ItemsCount%, INT((80 - (MenuLineLength% + 5)) / 2) + 1, 0
 PRINT CHR$(204) + STRING$(MenuLineLength% + 2, CHR$(205)) + CHR$(185);
 COLOR 14, 7
 LOCATE INT((25 - (ItemsCount% + 5)) / 2) + 3 + ItemsCount%, INT((80 - (MenuLineLength% + 5)) / 2) + 2, 0
 PRINT SPACE$(INT((MenuLineLength% - 56) / 2) + 1) + "Please press ENTER to select menu item or ESC to cancel."
 RETURN
END FUNCTION

FUNCTION MessageBox% (Title$, Message$)
 DIM OutMessage$
 DIM OutIndex%
 DIM WorkKey$
 IF LEN(Message$) < 256 THEN OutMessage$ = Message$ + SPACE$(256 - LEN(Message$)) ELSE OutMessage$ = LEFT$(Message$, 256)
 CALL MakeBox(7, 9, 64, 6)
 PRINT LEFT$(Title$, 64) + SPACE$(64 - LEN(LEFT$(Title$, 64)));
 COLOR 1, 7
 FOR OutIndex% = 1 TO 4
  LOCATE 10 + OutIndex%, 8, 0
  PRINT LEFT$(OutMessage$, 64);
  OutMessage$ = MID$(OutMessage$, 65)
 NEXT OutIndex%
 COLOR 14, 7
 LOCATE 15, 8, 0
 PRINT "Please press key is equalient to your answer: ENTER=Yes, ESC=No.";
 WorkKey$ = ""
 WHILE (WorkKey$ <> CHR$(13)) AND (WorkKey$ <> CHR$(27))
  WorkKey$ = INKEY$
 WEND
 MessageBox% = WorkKey$ = CHR$(13)
END FUNCTION

FUNCTION MonthDays% (MonthValue%, YearValue%)
 SELECT CASE MonthValue%
 CASE 1
   MonthDays% = 31
 CASE 2
   MonthDays% = 28 + IsLeapYear%(YearValue%)
 CASE 3
   MonthDays% = 31
 CASE 4
   MonthDays% = 30
 CASE 5
   MonthDays% = 31
 CASE 6
   MonthDays% = 30
 CASE 7
   MonthDays% = 31
 CASE 8
   MonthDays% = 31
 CASE 9
   MonthDays% = 30
 CASE 10
   MonthDays% = 31
 CASE 11
   MonthDays% = 30
 CASE 12
   MonthDays% = 31
 END SELECT
END FUNCTION

FUNCTION MonthDaysCount% (MonthValue%, YearValue%)
 SELECT CASE MonthValue%
 CASE 1
   MonthDaysCount% = 0
 CASE 2
   MonthDaysCount% = 31
 CASE 3
   MonthDaysCount% = 59 + IsLeapYear%(YearValue%)
 CASE 4
   MonthDaysCount% = 90 + IsLeapYear%(YearValue%)
 CASE 5
   MonthDaysCount% = 120 + IsLeapYear%(YearValue%)
 CASE 6
   MonthDaysCount% = 151 + IsLeapYear%(YearValue%)
 CASE 7
   MonthDaysCount% = 181 + IsLeapYear%(YearValue%)
 CASE 8
   MonthDaysCount% = 212 + IsLeapYear%(YearValue%)
 CASE 9
   MonthDaysCount% = 243 + IsLeapYear%(YearValue%)
 CASE 10
   MonthDaysCount% = 273 + IsLeapYear%(YearValue%)
 CASE 11
   MonthDaysCount% = 304 + IsLeapYear%(YearValue%)
 CASE 12
   MonthDaysCount% = 334 + IsLeapYear%(YearValue%)
 END SELECT
END FUNCTION

FUNCTION MonthName$ (MonthNumber%)
 SELECT CASE MonthNumber%
 CASE 1
   MonthName$ = "January"
 CASE 2
   MonthName$ = "February"
 CASE 3
   MonthName$ = "March"
 CASE 4
   MonthName$ = "April"
 CASE 5
   MonthName$ = "May"
 CASE 6
   MonthName$ = "June"
 CASE 7
   MonthName$ = "July"
 CASE 8
   MonthName$ = "August"
 CASE 9
   MonthName$ = "September"
 CASE 10
   MonthName$ = "October"
 CASE 11
   MonthName$ = "November"
 CASE 12
   MonthName$ = "December"
 END SELECT
END FUNCTION

SUB OutBox (Title$, Message$)
 DIM OutMessage$
 DIM OutIndex%
 IF LEN(Message$) < 256 THEN OutMessage$ = Message$ + SPACE$(256 - LEN(Message$)) ELSE OutMessage$ = LEFT$(Message$, 256)
 CALL MakeBox(7, 9, 64, 6)
 PRINT LEFT$(Title$, 64) + SPACE$(64 - LEN(LEFT$(Title$, 64)));
 COLOR 1, 7
 FOR OutIndex% = 1 TO 4
  LOCATE 10 + OutIndex%, 8, 0
  PRINT LEFT$(OutMessage$, 64);
  OutMessage$ = MID$(OutMessage$, 65)
 NEXT OutIndex%
 COLOR 14, 7
 LOCATE 15, 8, 0
 PRINT "       Please press the ENTER key to quit from this box.";
 WHILE INKEY$ <> CHR$(13)
 WEND
END SUB

FUNCTION PasswordInputBox% (Title$, Message$, InputTextLine$)
 DIM OutMessage$
 DIM OutIndex%
 DIM WorkKey$
 DIM InputTextCursorColumn%
 DIM InputTextCursorPosition%
 DIM InputText$
 IF LEN(Message$) < 256 THEN OutMessage$ = Message$ + SPACE$(256 - LEN(Message$)) ELSE OutMessage$ = LEFT$(Message$, 256)
 CALL MakeBox(7, 8, 64, 7)
 PRINT LEFT$(Title$, 64) + SPACE$(64 - LEN(LEFT$(Title$, 64)));
 COLOR 1, 7
 FOR OutIndex% = 1 TO 4
  LOCATE 9 + OutIndex%, 8, 0
  PRINT LEFT$(OutMessage$, 64);
  OutMessage$ = MID$(OutMessage$, 65)
 NEXT OutIndex%
 COLOR 14, 7
 LOCATE 15, 8, 0
 PRINT "Please press key is equalient to your answer: ENTER=Yes, ESC=No.";
 InputTextCursorColumn% = 1
 InputTextCursorPosition% = 1
 InputText$ = InputTextLine$
 GOSUB PasswordOutInputLine
 DO
  WorkKey$ = INKEY$
  SELECT CASE LEN(WorkKey$)
  CASE 1
    SELECT CASE WorkKey$
    CASE CHR$(8)
      IF InputTextCursorColumn% > 1 THEN
       InputTextCursorColumn% = InputTextCursorColumn% - 1
       InputTextCursorPosition% = InputTextCursorPosition% - 1
       IF InputTextCursorColumn% < 1 THEN InputTextCursorColumn% = 1
       IF InputTextCursorPosition% < 1 THEN InputTextCursorPosition% = 1
       InputText$ = MID$(InputText$, 1, InputTextCursorColumn% - 1) + MID$(InputText$, InputTextCursorColumn% + 1)
       GOSUB PasswordOutInputLine
      END IF
    CASE CHR$(13)
      InputTextLine$ = InputText$
      EXIT DO
    CASE CHR$(27)
      EXIT DO
    CASE ELSE
      IF (LEN(InputText$) < 256) AND (ASC(WorkKey$) > (ASC(SPACE$(1)) - 1)) THEN
       InputText$ = MID$(InputText$, 1, InputTextCursorColumn% - 1) + WorkKey$ + MID$(InputText$, InputTextCursorColumn%)
       InputTextCursorColumn% = InputTextCursorColumn% + 1
       InputTextCursorPosition% = InputTextCursorPosition% + 1
       IF InputTextCursorColumn% > LEN(InputText$) + 1 THEN InputTextCursorColumn% = LEN(InputText$) + 1
       IF LEN(InputText$) > 63 THEN IF InputTextCursorPosition% > 64 THEN InputTextCursorPosition% = 64
       IF LEN(InputText$) < 65 THEN IF InputTextCursorPosition% > LEN(InputText$) + 1 THEN InputTextCursorPosition% = LEN(InputText$) + 1
       GOSUB PasswordOutInputLine
      END IF
    END SELECT
  CASE 2
    WorkKey$ = MID$(WorkKey$, 2)
    SELECT CASE WorkKey$
    CASE CHR$(75)
      IF InputTextCursorColumn% > 1 THEN
       InputTextCursorColumn% = InputTextCursorColumn% - 1
       InputTextCursorPosition% = InputTextCursorPosition% - 1
       IF InputTextCursorColumn% < 1 THEN InputTextCursorColumn% = 1
       IF InputTextCursorPosition% < 1 THEN InputTextCursorPosition% = 1
       GOSUB PasswordOutInputLine
      END IF
    CASE CHR$(77)
      IF InputTextCursorColumn% < LEN(InputText$) + 1 THEN
       InputTextCursorColumn% = InputTextCursorColumn% + 1
       InputTextCursorPosition% = InputTextCursorPosition% + 1
       IF InputTextCursorColumn% > LEN(InputText$) + 1 THEN InputTextCursorColumn% = LEN(InputText$) + 1
       IF LEN(InputText$) > 63 THEN IF InputTextCursorPosition% > 64 THEN InputTextCursorPosition% = 64
       IF LEN(InputText$) < 65 THEN IF InputTextCursorPosition% > LEN(InputText$) + 1 THEN InputTextCursorPosition% = LEN(InputText$) + 1
       GOSUB PasswordOutInputLine
      END IF
    CASE CHR$(71)
      IF InputTextCursorColumn% <> 1 THEN
       InputTextCursorColumn% = 1
       InputTextCursorPosition% = 1
       GOSUB PasswordOutInputLine
      END IF
    CASE CHR$(79)
      IF InputTextCursorColumn% <> LEN(InputText$) + 1 THEN
       InputTextCursorColumn% = LEN(InputText$) + 1
       InputTextCursorPosition% = LEN(InputText$) + 1
       IF LEN(InputText$) > 63 THEN IF InputTextCursorPosition% > 64 THEN InputTextCursorPosition% = 64
       IF LEN(InputText$) < 65 THEN IF InputTextCursorPosition% > LEN(InputText$) + 1 THEN InputTextCursorPosition% = LEN(InputText$) + 1
       GOSUB PasswordOutInputLine
      END IF
    CASE CHR$(83)
      IF InputText$ <> "" THEN
       InputText$ = MID$(InputText$, 1, InputTextCursorColumn% - 1) + MID$(InputText$, InputTextCursorColumn% + 1)
       GOSUB PasswordOutInputLine
      END IF
    END SELECT
  END SELECT
 LOOP
 LOCATE , , 0
 PasswordInputBox% = WorkKey$ = CHR$(13)
 EXIT FUNCTION
PasswordOutInputLine:
 COLOR 4, 7
 LOCATE 14, 8, 0
 PRINT STRING$(LEN(MID$(InputText$, (InputTextCursorColumn% - InputTextCursorPosition%) + 1, 64)), "*") + SPACE$(64 - LEN(MID$(InputText$, (InputTextCursorColumn% - InputTextCursorPosition%) + 1, 64)));
 LOCATE 14, 7 + InputTextCursorPosition%, 1, 7, 8
 RETURN
END FUNCTION

SUB Rotate (WorkKeyData%())
 DIM Index%
 CALL LetBe(RotateData%(), WorkKeyData%(), 56)
 FOR Index% = 1 TO 55
  RotateData%(Index%) = RotateData%(Index% + 1)
 NEXT Index%
 RotateData%(28) = WorkKeyData%(1)
 RotateData%(56) = WorkKeyData%(29)
 CALL LetBe(WorkKeyData%(), RotateData%(), 56)
END SUB

SUB ScratchScreen
 COLOR 0, 2
 CLS
 PRINT "********************************************************************************"
 PRINT "                The Standart GNU Personal Data Encryption Utility."
 PRINT "                     Copyright (C) Sandul Yura Valentinovich."
 PRINT "                        (R) Wednesday, 5 March 2003 year."
 PRINT
 PRINT "    This program is free software; you can redistribute it and/or modify it"
 PRINT "under the terms of the GNU General Public License as published by the Free"
 PRINT "Software Foundation; either version 2 of the License, or (at your option) any"
 PRINT "later version."
 PRINT "    This program is distributed in the hope that it will be useful, but WITHOUT"
 PRINT "ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS"
 PRINT "FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details."
 PRINT "    You should have received a copy of the GNU General Public License along with"
 PRINT "this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave,"
 PRINT "Cambridge, MA 02139, USA."
END SUB

SUB SecondsToDateAndTime (SecondsCount#, HourValue%, MinuteValue%, SecondValue%, DayValue%, MonthValue%, YearValue%, DayOfWeekValue%)
 DIM WorkValue#
 WorkValue# = SecondsCount#
 YearValue% = INT(WorkValue# / (416 * 86400))
 WorkValue# = WorkValue# - (YearValue% * (416 * 86400#))
 MonthValue% = INT(WorkValue# / (32 * 86400))
 WorkValue# = WorkValue# - (MonthValue% * (32 * 86400))
 DayValue% = INT(WorkValue# / 86400)
 WorkValue# = WorkValue# - (DayValue% * 86400)
 HourValue% = INT(WorkValue# / 3600)
 WorkValue# = WorkValue# - (HourValue% * 3600!)
 MinuteValue% = INT(WorkValue# / 60)
 SecondValue% = WorkValue# - (MinuteValue% * 60)
 DayOfWeekValue% = DayOfWeek%(DayValue%, MonthValue%, YearValue%)
END SUB

SUB StringToBits (InLine$, Bits%())
 DIM Index%
 DIM SubIndex%
 DIM TempLine$
 FOR Index% = 1 TO 8
  TempLine$ = Bin$(ASC(MID$(InLine$, Index%, 1)))
  FOR SubIndex% = 1 TO 8
   Bits%(((Index% - 1) * 8) + SubIndex%) = ASC(MID$(TempLine$, SubIndex%, 1)) - ASC("0")
  NEXT SubIndex%
 NEXT Index%
END SUB

SUB Transpose (DESData%(), Work%(), Count%)
 DIM Index%
 DIM TempData%(64)
 CALL LetBe(TempData%(), DESData%(), 64)
 FOR Index% = 1 TO Count%
  DESData%(Index%) = TempData%(Work%(Index%))
 NEXT Index%
END SUB

SUB UnCompute (Index%, DESData%(), InData%(), OutData%())
 DIM Temp%
 DIM SubIndex%
 DIM WorkIndex%
 DIM WorkData%
 Temp% = Index%
 CALL LetBe(ComputeData%(), InData%(), 64)
 CALL Transpose(ComputeData%(), Enumerated%(), 48)
 CALL LetBe(CryptData%(), DESData%(), 64)
 CALL Transpose(CryptData%(), CryptWork%(), 48)
 FOR SubIndex% = 1 TO Rots%(Temp%)
  CALL UnRotate(DESData%())
 NEXT SubIndex%
 FOR SubIndex% = 1 TO 48
  IF (ComputeData%(SubIndex%) + CryptData%(SubIndex%) = 1) THEN WorkCryptData%(SubIndex%) = 1 ELSE WorkCryptData%(SubIndex%) = 0
 NEXT SubIndex%
 FOR WorkIndex% = 1 TO 8
  WorkData% = (32 * WorkCryptData%((6 * WorkIndex%) - 5)) + (16 * WorkCryptData%(6 * WorkIndex%)) + (8 * WorkCryptData%((6 * WorkIndex%) - 4)) + (4 * WorkCryptData%((6 * WorkIndex%) - 3)) + (2 * WorkCryptData%((6 * WorkIndex%) - 2)) + WorkCryptData%((6 * WorkIndex%) - 1) + 1
  IF (INT(Work%(WorkIndex%, WorkData%) / 8) MOD 2) THEN OutData%((4 * WorkIndex%) - 3) = 1 ELSE OutData%((4 * WorkIndex%) - 3) = 0
  IF (INT(Work%(WorkIndex%, WorkData%) / 4) MOD 2) THEN OutData%((4 * WorkIndex%) - 2) = 1 ELSE OutData%((4 * WorkIndex%) - 2) = 0
  IF (INT(Work%(WorkIndex%, WorkData%) / 2) MOD 2) THEN OutData%((4 * WorkIndex%) - 1) = 1 ELSE OutData%((4 * WorkIndex%) - 1) = 0
  IF (Work%(WorkIndex%, WorkData%) MOD 2) THEN OutData%(4 * WorkIndex%) = 1 ELSE OutData%(4 * WorkIndex%) = 0
 NEXT WorkIndex%
 CALL Transpose(OutData%(), Pointers%(), 32)
END SUB

FUNCTION UnDESWork$ (InLine$, PasswordLine$)
 DIM TempLine$
 DIM Index%
 DIM SubIndex%
 TempLine$ = ""
 CALL StringToBits(InLine$, HyperText%())
 CALL StringToBits(PasswordLine$, Password%())
 CALL LetBe(InDESData%(), HyperText%(), 64)
 CALL Transpose(InDESData%(), BeginData%(), 64)
 CALL Transpose(InDESData%(), SwapData%(), 64)
 CALL Transpose(Password%(), KeyData%(), 56)
 FOR Index% = 16 TO 1 STEP -1
  CALL LetBe(OutDESData%(), InDESData%(), 64)
  CALL UnCompute(Index%, Password%(), OutDESData%(), WorkDESData%())
  FOR SubIndex% = 1 TO 32
   IF (OutDESData%(SubIndex% + 32) + WorkDESData%(SubIndex%) = 1) THEN InDESData%(SubIndex%) = 1 ELSE InDESData%(SubIndex%) = 0
  NEXT SubIndex%
  FOR SubIndex% = 33 TO 64
   InDESData%(SubIndex%) = OutDESData%(SubIndex% - 32)
  NEXT SubIndex%
 NEXT Index%
 CALL Transpose(InDESData%(), EndData%(), 64)
 CALL LetBe(PlainText%(), InDESData%(), 64)
 CALL BitsToString(PlainText%(), TempLine$)
 UnDESWork$ = TempLine$
END FUNCTION

SUB UnRotate (WorkKeyData%())
 DIM Index%
 CALL LetBe(RotateData%(), WorkKeyData%(), 56)
 FOR Index% = 56 TO 2 STEP -1
  RotateData%(Index%) = RotateData%(Index% - 1)
 NEXT Index%
 RotateData%(1) = WorkKeyData%(28)
 RotateData%(29) = WorkKeyData%(56)
 CALL LetBe(WorkKeyData%(), RotateData%(), 56)
END SUB

