It is currently Tue Mar 09, 2021 9:50 am

All times are UTC + 1 hour




Post new topic Reply to topic  [ 47 posts ]  Go to page Previous  1, 2, 3, 4  Next
Author Message
 Post subject: Re: Rabbit Cipher - Module
PostPosted: Fri Nov 06, 2020 9:59 am 
Offline
Enthusiast
Enthusiast
User avatar

Joined: Sun Jul 07, 2013 11:35 am
Posts: 587
Location: Canada
wilbert wrote:
I'll try to create a working asm version as well.
Some prefer the speed of asm, others the readability of normal basic code.
But it might help to compare the results of the two against each other.


I'm curious if your ASM version will be much faster. It's pretty fast as is already.

I have just uploaded the version 4. This version might be the last update about correcting issues.

See first post.

Best regards
StarBootics

_________________
The Stone Age did not end due to a shortage of stones !


Top
 Profile  
Reply with quote  
 Post subject: Re: Rabbit Cipher - Module
PostPosted: Fri Nov 06, 2020 12:39 pm 
Offline
PureBasic Expert
PureBasic Expert

Joined: Sun Aug 08, 2004 5:21 am
Posts: 3712
Location: Netherlands
StarBootics wrote:
I'm curious if your ASM version will be much faster. It's pretty fast as is already.

It will be a lot faster but it also depends on how you compile your code (32 or 64 bit).
For the asm version there will be little difference between 32 or 64 bit but with your code there's a big speed difference between the two.

_________________
macOS 10.15 Catalina, Windows 10


Top
 Profile  
Reply with quote  
 Post subject: Re: Rabbit Cipher - Module
PostPosted: Fri Nov 06, 2020 7:13 pm 
Offline
Enthusiast
Enthusiast
User avatar

Joined: Sun Jul 07, 2013 11:35 am
Posts: 587
Location: Canada
Quote:
It will be a lot faster but it also depends on how you compile your code (32 or 64 bit).
For the asm version there will be little difference between 32 or 64 bit but with your code there's a big speed difference between the two.

In my code even if I have a 64-bit computer the Xor is being done on 64-bit instead of 32-bit, I have 32-bit of Xoring of complete waste. I know my code is just a serious hacking session and my knowledge of ASM is near zero so for the ASM version I can't help you.

Best regards
StarBootics

_________________
The Stone Age did not end due to a shortage of stones !


Top
 Profile  
Reply with quote  
 Post subject: Re: Rabbit Cipher - Module
PostPosted: Sat Nov 07, 2020 8:02 am 
Offline
PureBasic Expert
PureBasic Expert

Joined: Sun Aug 08, 2004 5:21 am
Posts: 3712
Location: Netherlands
Here's an asm optimized implementation you can play with ...

Module :
Code:
;==================================
; Module:          Rabbit
; Author:          Wilbert
; Date:            Nov 12, 2020
;==================================

DeclareModule Rabbit
 
  ;-RabbitCtx structure
  Structure RabbitCtx
    X.l[8]  ; State
    C.l[8]  ; Counters
    Carry.l ; Carry for counters
  EndStructure
 
  ;-Exported functions
  Declare SetKeyAndIV(*Ctx.RabbitCtx, *Key, *IV)
  Declare ProcessBytes(*Ctx.RabbitCtx, *Input, *Output, Size)
  Declare CryptMemory(*Input, *Output, Size, *Key, *InitVector = #Null)
 
EndDeclareModule


Module Rabbit
  DisableDebugger
  EnableExplicit
  EnableASM
 
  ;- Private structures
 
  Structure Mem64Byte
    l.l[16]
  EndStructure
   
  ;- Private macros
 
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
    Macro rbx : ebx : EndMacro  ; replace rbx with ebx on x86
    Macro rcx : ecx : EndMacro  ; replace rcx with ecx on x86
    Macro rdx : edx : EndMacro  ; replace rdx with edx on x86
    Macro rsi : esi : EndMacro  ; replace rsi with esi on x86
    Macro rdi : edi : EndMacro  ; replace rdi with edi on x86
    Macro rsp : esp : EndMacro  ; replace rsp with esp on x86
  CompilerEndIf 
 
  Macro M_AddWithCarry(n, v)
    mov eax, [rcx + n*4 + 32]   ; get c[n]
    adc eax, v                  ; add with carry v
    mov [rcx + n*4 + 32], eax   ; set c[n]
  EndMacro
 
  Macro M_GFunction(n)
    mov eax, [rcx + n*4]        ; get x[n]
    add eax, [rcx + n*4 + 32]   ; add c[n]
    mul eax                     ; eax*eax, result edx:eax
    XOr eax, edx                ; xor lower and upper result bits
    mov [rsp + n*4], eax        ; set g[n]
  EndMacro 
 
  Macro M_NewStateValue(n, n1, r1, n2, r2)
    mov eax, [rsp + n1*4]       ; get g[n1]
    mov edx, [rsp + n2*4]       ; get g[n2]
    rol eax, r1                 ; rol n1, r1
    CompilerIf r2
      rol edx, r2               ; rol n2, r2
    CompilerEndIf
    add eax, edx                ; add together
    add eax, [rsp + n*4]        ; add g[n]
    mov [rcx + n*4], eax        ; set x[n]
  EndMacro
 
  Macro M_SetStateAndCounter(k, n1, n2)
    CompilerIf k = 14           ; get key bits
      mov eax, [rdx]
      shl eax, 16
      Or ax, [rdx + 14]
    CompilerElse
      mov eax, [rdx + k]
    CompilerEndIf
    mov [rcx + n1*4], eax       ; set x[n1]
    rol eax, 16
    mov [rcx + n2*4 + 32], eax  ; set c[n2]
  EndMacro
 
  Macro M_ModifyCounter(n1, n2)
    mov eax, [rcx + n2*4]       ; get x[n2]
    XOr [rcx + n1*4 + 32], eax  ; c[n1] ! x[n2]
  EndMacro
 
  Macro M_XorStreamBytes(n1, n2, n3, n4, f=0)
    mov eax, [rcx + n3*4]       ; get x[n3]
    mov edx, [rcx + n4*4]       ; get x[n4]
    shrd eax, edx, 16           ; (x[n3] >> 16) | (x[n4] << 16)
    XOr eax, [rcx + n2*4]       ; xor x[n2]
    CompilerIf f=0
      XOr eax, [rsi + n1*4]
      mov [rdi + n1*4], eax
    CompilerElse
      mov [rsp + n1*4], eax
    CompilerEndIf
  EndMacro
 
  ;- Public functions

  Procedure SetKeyAndIV(*Ctx.RabbitCtx, *Key, *IV)
    Protected M.Mem64Byte
   
    ; *Key : Pointer to 128 bit key
    ; *IV  : Pointer to 64 bit initialization vector
   
    mov rcx, [p.p_Ctx]
    mov rdx, [p.p_Key]
   
    ; Generate initial state and counter values
    M_SetStateAndCounter( 0, 0, 4)
    M_SetStateAndCounter( 2, 5, 1)
    M_SetStateAndCounter( 4, 2, 6)
    M_SetStateAndCounter( 6, 7, 3)
    M_SetStateAndCounter( 8, 4, 0)
    M_SetStateAndCounter(10, 1, 5)
    M_SetStateAndCounter(12, 6, 2)
    M_SetStateAndCounter(14, 3, 7)
   
    ; Reset carry flag
    mov dword [rcx + 64], 0
   
    ; Process 64 bytes
    ProcessBytes(*Ctx, @M, @M, 64)
   
    ; Modify counters
    mov rcx, [p.p_Ctx]
    M_ModifyCounter(0, 4)
    M_ModifyCounter(1, 5)
    M_ModifyCounter(2, 6)
    M_ModifyCounter(3, 7)
    M_ModifyCounter(4, 0)
    M_ModifyCounter(5, 1)
    M_ModifyCounter(6, 2)
    M_ModifyCounter(7, 3)

    If *IV
      ; Modify counter values
      mov rcx, [p.p_Ctx]
      mov rdx, [p.p_IV]
      mov eax, [rdx]
      mov edx, [rdx + 4]
      XOr [rcx + 32], eax
      XOr [rcx + 40], edx
      XOr [rcx + 48], eax
      XOr [rcx + 56], edx
      rol edx, 16
      xchg ax, dx
      rol eax, 16
      XOr [rcx + 36], eax
      XOr [rcx + 44], edx
      XOr [rcx + 52], eax
      XOr [rcx + 60], edx
      ; Process 64 bytes
      ProcessBytes(*Ctx, @M, @M, 64)
    EndIf
   
  EndProcedure
 
  Procedure ProcessBytes(*Ctx.RabbitCtx, *Input, *Output, Size)
    Protected.i reg_bx, reg_si, reg_di
    If Size
      mov [p.v_reg_bx], rbx
      mov [p.v_reg_si], rsi
      mov [p.v_reg_di], rdi
      mov rcx, [p.p_Ctx]    ; rcx = *Ctx
      mov rsi, [p.p_Input]  ; rsi = *Input
      mov rdi, [p.p_Output] ; rdi = *Output
      mov rbx, [p.v_Size]   ; rbx = Size
      sub rsp, 32           ; alloc g space
      !.loop16b:
     
      ; Calculate new counter values
      mov edx, [rcx + 64] ; load carry
      shr edx, 1
      M_AddWithCarry(0, 0x4d34d34d)
      M_AddWithCarry(1, 0xd34d34d3)
      M_AddWithCarry(2, 0x34d34d34)
      M_AddWithCarry(3, 0x4d34d34d)
      M_AddWithCarry(4, 0xd34d34d3)
      M_AddWithCarry(5, 0x34d34d34)
      M_AddWithCarry(6, 0x4d34d34d)
      M_AddWithCarry(7, 0xd34d34d3)
      adc edx, edx
      mov [rcx + 64], edx ; save carry
     
      ; Calculate the g-functions
      M_GFunction(0)
      M_GFunction(1)
      M_GFunction(2)
      M_GFunction(3)
      M_GFunction(4)
      M_GFunction(5)
      M_GFunction(6)
      M_GFunction(7)
     
      ; Calculate new state values
      M_NewStateValue(0, 7, 16, 6, 16)
      M_NewStateValue(1, 0,  8, 7,  0)
      M_NewStateValue(2, 1, 16, 0, 16)
      M_NewStateValue(3, 2,  8, 1,  0)
      M_NewStateValue(4, 3, 16, 2, 16)
      M_NewStateValue(5, 4,  8, 3,  0)
      M_NewStateValue(6, 5, 16, 4, 16)
      M_NewStateValue(7, 6,  8, 5,  0)
     
      ; Xor stream bytes
      sub rbx, 16
      !jc .final
      M_XorStreamBytes(0, 0, 5, 3)
      M_XorStreamBytes(1, 2, 7, 5)
      M_XorStreamBytes(2, 4, 1, 7)
      M_XorStreamBytes(3, 6, 3, 1)
      add rsi, 16
      add rdi, 16
      test rbx, rbx
      !jnz .loop16b
      !jmp .done
      !.final:
      M_XorStreamBytes(0, 0, 5, 3, 1)
      M_XorStreamBytes(1, 2, 7, 5, 1)
      M_XorStreamBytes(2, 4, 1, 7, 1)
      M_XorStreamBytes(3, 6, 3, 1, 1)
      add rbx, 15
      !.loop1b:
      movzx eax, byte [rsi + rbx]
      XOr al, [rsp + rbx]
      mov [rdi + rbx], al
      sub rbx, 1
      !jnc .loop1b
      !.done:
     
      add rsp, 32
      mov rbx, [p.v_reg_bx]
      mov rsi, [p.v_reg_si]
      mov rdi, [p.v_reg_di]
    EndIf
  EndProcedure
 
 
  Procedure CryptMemory(*Input, *Output, Size, *Key, *InitVector = #Null)
    ; Encrypt/decrypt a block of memory
    ; ---------------------------------   
    ; *Key : Pointer to 128 bit key
    ; *IV  : Pointer to 64 bit initialization vector   
    Protected Ctx.RabbitCtx
    SetKeyAndIV(@Ctx, *Key, *InitVector)
    ProcessBytes(@Ctx, *Input, *Output, Size)
  EndProcedure
 
EndModule




Test vectors :
Code:
DataSection
  ; Test vectors
 
  Key1:
  Data.a $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
  Out1:
  Data.a $02,$F7,$4A,$1C,$26,$45,$6B,$F5,$EC,$D6,$A5,$36,$F0,$54,$57,$B1
  Data.a $A7,$8A,$C6,$89,$47,$6C,$69,$7B,$39,$0C,$9C,$C5,$15,$D8,$E8,$88
  Data.a $96,$D6,$73,$16,$88,$D1,$68,$DA,$51,$D4,$0C,$70,$C3,$A1,$16,$F4
 
  Key2:
  Data.a $C2,$1F,$CF,$38,$81,$CD,$5E,$E8,$62,$8A,$CC,$B0,$A9,$89,$0D,$F8
  Out2:
  Data.a $3D,$02,$E0,$C7,$30,$55,$91,$12,$B4,$73,$B7,$90,$DE,$E0,$18,$DF
  Data.a $CD,$6D,$73,$0C,$E5,$4E,$19,$F0,$C3,$5E,$C4,$79,$0E,$B6,$C7,$4A
  Data.a $B0,$BB,$1B,$B7,$86,$0A,$68,$5A,$BF,$9C,$8F,$AF,$26,$3C,$CA,$09

  Key3:
  Data.a $1D,$27,$2C,$6A,$2D,$8E,$3D,$FC,$AC,$14,$05,$6B,$78,$D6,$33,$A0
  Out3:
  Data.a $A3,$A9,$7A,$BB,$80,$39,$38,$20,$B7,$E5,$0C,$4A,$BB,$53,$82,$3D
  Data.a $C4,$42,$37,$99,$C2,$EF,$C9,$FF,$B3,$A4,$12,$5F,$1F,$4C,$99,$A8
  Data.a $AE,$95,$3E,$56,$D3,$8B,$D2,$67,$67,$C3,$64,$9E,$EF,$34,$D9,$19
 
  Key4:
  Data.a $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
  IV4:
  Data.a $00,$00,$00,$00,$00,$00,$00,$00
  Out4:
  Data.a $ED,$B7,$05,$67,$37,$5D,$CD,$7C,$D8,$95,$54,$F8,$5E,$27,$A7,$C6
  Data.a $8D,$4A,$DC,$70,$32,$29,$8F,$7B,$D4,$EF,$F5,$04,$AC,$A6,$29,$5F
  Data.a $66,$8F,$BF,$47,$8A,$DB,$2B,$E5,$1E,$6C,$DE,$29,$2B,$82,$DE,$2A 
 
  Key5:
  Data.a $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
  IV5:
  Data.a $59,$7E,$26,$C1,$75,$F5,$73,$C3
  Out5:
  Data.a $6D,$7D,$01,$22,$92,$CC,$DC,$E0,$E2,$12,$00,$58,$B9,$4E,$CD,$1F
  Data.a $2E,$6F,$93,$ED,$FF,$99,$24,$7B,$01,$25,$21,$D1,$10,$4E,$5F,$A7
  Data.a $A7,$9B,$02,$12,$D0,$BD,$56,$23,$39,$38,$E7,$93,$C3,$12,$C1,$EB 
 
  Key6:
  Data.a $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
  IV6:
  Data.a $27,$17,$F4,$D2,$1A,$56,$EB,$A6
  Out6:
  Data.a $4D,$10,$51,$A1,$23,$AF,$B6,$70,$BF,$8D,$85,$05,$C8,$D8,$5A,$44
  Data.a $03,$5B,$C3,$AC,$C6,$67,$AE,$AE,$5B,$2C,$F4,$47,$79,$F2,$C8,$96
  Data.a $CB,$51,$15,$F0,$34,$F0,$3D,$31,$17,$1C,$A7,$5F,$89,$FC,$CB,$9F
 
EndDataSection


Procedure VerifyTestVector(*Key, *IV, *Out, VectorName.s)
  Protected Dim Stream.a(47)
  Protected Ctx.Rabbit::RabbitCtx
  Protected.i i, *a.Ascii = *Out
 
  Rabbit::SetKeyAndIV(@Ctx, *Key, *IV)
  Rabbit::ProcessBytes(@Ctx, @Stream(), @Stream(), 48)
  For i = 0 To 47
    If Stream(i) <> *a\a
      Debug VectorName + " [ERROR]"
      ProcedureReturn
    EndIf
    *a + 1
  Next
  Debug VectorName + " [ok]"
 
EndProcedure

VerifyTestVector(?Key1, #Null, ?Out1, "Vector 1")
VerifyTestVector(?Key2, #Null, ?Out2, "Vector 2")
VerifyTestVector(?Key3, #Null, ?Out3, "Vector 3")
VerifyTestVector(?Key4, ?IV4, ?Out4, "Vector 4")
VerifyTestVector(?Key5, ?IV5, ?Out5, "Vector 5")
VerifyTestVector(?Key6, ?IV6, ?Out6, "Vector 6")



Another small example
Code:
DataSection
  MasterKey:
  Data.a $1D,$27,$2C,$6A,$2D,$8E,$3D,$FC,$AC,$14,$05,$6B,$78,$D6,$33,$A0
EndDataSection

Define.Rabbit::RabbitCtx Master, Work
Define.q TestValue, Encrypted, Decrypted

Rabbit::SetKeyAndIV(@Master, ?MasterKey, #Null)

TestValue = $1234567890abcdef

Work = Master
Rabbit::ProcessBytes(@Work, @TestValue, @Encrypted, 8)

Work = Master
Rabbit::ProcessBytes(@Work, @Encrypted, @Decrypted, 8)

Debug TestValue
Debug Encrypted
Debug Decrypted



Nov 8 update: Small improvement to the code of IVSsetup
Nov 11 update: Combined key and iv setup into one procedure
Nov 12 update: Integrated NextState into ProcessBytes for performance improvement

_________________
macOS 10.15 Catalina, Windows 10


Last edited by wilbert on Fri Nov 13, 2020 3:10 pm, edited 3 times in total.

Top
 Profile  
Reply with quote  
 Post subject: Re: Rabbit Cipher - Module
PostPosted: Sun Nov 08, 2020 5:54 pm 
Offline
Enthusiast
Enthusiast
User avatar

Joined: Sun Jul 07, 2013 11:35 am
Posts: 587
Location: Canada
Hello everyone,

@wilbert : Nice job with your ASM version !

As promised there is a convenient Read/Write on file OOP style library.

EDIT 1 : Minor correction related to Unsigned value. ReadU32()/WriteU32() added and RC_ReadString() / RC_WriteString() modified.
EDIT 2 : Minor modification for speed improvement about the Addition() procedure.

Best regards
StarBootics
Code:
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; AUTOMATICALLY GENERATED CODE, DO NOT MODIFY
; UNLESS YOU REALLY, REALLY, REALLY MEAN IT !!
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; Code generated by : Dev-Object - V1.2.0
; Project name : Read Write RabbitCipher
; File name : Read Write RabbitCipher 128 - OOP.pb
; File Version : 1.0.2
; Programmation : OK
; Programmed by : StarBootics
; Creation Date : Noverber 8th, 2020
; Last update : November 8th, 2020
; Coded for PureBasic : V5.73 beta 2
; Platform : Windows, Linux, MacOS X
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; Programming notes
;
; 1. Rabbit was designed by Martin Boesgaard, Mette Vesterager,
;    Thomas Pedersen, Jesper Christiansen and Ove Scavenius.
;
;    https://www.ecrypt.eu.org/stream/rabbitpf.html
;
; 2. Type of Algorithm : Synchronous Stream Cipher
;
; 3. Rabbit has been released into the public domain and may
;    be used freely for any purpose.
;
; 4. I deserve credit only for porting Rabbit Cipher from C to
;    PureBasic. I'm not the original designer of the algorithm
;    so no credit to me for that.
;
; 5. The software is provided "as is" without any express or
;    implied warranty. You are using it at your own risk. The
;    original authors and/or me shall not in any way be liable
;    for any use of this software.
;
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

DeclareModule RabbitCipher

  Interface RabbitCipher
   
    GetKey.s()
    GetInitVector.s()
    SetKey(P_Key.s)
    SetInitVector(P_InitVector.s)
   
    RC_WriteString(FileID.i, P_String.s)
    RC_WriteByte(FileID.i, P_Value.b)
    RC_WriteAsciiCharacter(FileID.i, P_Value.a)
    RC_WriteWord(FileID.i, P_Value.w)
    RC_WriteUnicodeCharacter(FileID.i, P_Value.u)
    RC_WriteCharacter(FileID.i, P_Value.c)
    RC_WriteLong(FileID.i, P_Value.l)
    RC_WriteQuad(FileID.i, P_Value.q)
    RC_WriteInteger(FileID.i, P_Value.i)
    RC_WriteFloat(FileID.i, P_Value.f)
    RC_WriteDouble(FileID.i, P_Value.d)
   
    RC_ReadString.s(FileID.i)
    RC_ReadByte.b(FileID.i)
    RC_ReadAsciiCharacter.a(FileID.i)
    RC_ReadWord.w(FileID.i)
    RC_ReadUnicodeCharacter.u(FileID.i)
    RC_ReadCharacter.c(FileID.i)
    RC_ReadLong.l(FileID.i)
    RC_ReadQuad.q(FileID.i)
    RC_ReadInteger.i(FileID.i)
    RC_ReadFloat.f(FileID.i)
    RC_ReadDouble.d(FileID.i)
   
    Free()
   
  EndInterface
 
  Declare.i New(P_Key.s = "RabbitCipher", P_InitVector.s = "InitVector")
 
EndDeclareModule

Module RabbitCipher
 
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Structures declaration <<<<<

  Structure Private_Members
   
    VirtualTable.i
    Key.s
    InitVector.s
   
  EndStructure
 
  Structure Rabbit128
   
    X.q[8]
    C.q[8]
    Carry.q
   
  EndStructure

  Structure Temp128
   
    g.q[8]
    OldC.q[8]
   
  EndStructure

  Structure Buffer128
   
    Buffer.a[16]
   
  EndStructure

  Structure Core128
   
    Master.Rabbit128
    Work.Rabbit128
   
  EndStructure

  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Macros declaration <<<<<
 
  Macro U32V(v)
   
    ((v) & $FFFFFFFF)
   
  EndMacro
 
  Macro ROTL32(v, n)
   
    (U32V((v) << (n)) | ((v) >> (32 - (n))))
   
  EndMacro
 
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Procedures declaration (Private) <<<<<
 
  Procedure.s Normalizer(Input.s, BitsLength.l)
   
    Bytes.l = BitsLength >> 3
    Output.s = StringFingerprint(Input, #PB_Cipher_MD5)
   
    While StringByteLength(Output) < Bytes
      Output + StringFingerprint(Output, #PB_Cipher_MD5)
    Wend
   
    ProcedureReturn Left(Output, Bytes / SizeOf(Unicode))
  EndProcedure
 
  Procedure.q PeekU32(*Buffer)
   
    ; Even if a quad size is 64-bit, we are
    ; interested only by the first 32-bit.
   
    CopyMemory(*Buffer, @Var.q, 4)
   
    ProcedureReturn Var
  EndProcedure
 
  Procedure PokeU32(*Buffer, Var.q)
   
    ; Even if a quad size is 64-bit, we are
    ; interested only by the first 32-bit.
   
    CopyMemory(@Var, *Buffer, 4)
   
  EndProcedure

  Procedure.q ReadU32(FileID.i)

    ; Even if a quad size is 64-bit, we are
    ; interested only by the first 32-bit.

    ReadData(FileID, @Var.q, 4)
   
    ProcedureReturn Var
  EndProcedure
 
  Procedure WriteU32(FileID.i, Var.q)
   
    ; Even if a quad size is 64-bit, we are
    ; interested only by the first 32-bit.

    WriteData(FileID, @Var, 4)
   
  EndProcedure

  Procedure.q U8TO32_LITTLE(*p)
   
    B0.a = PeekA(*p+0)
    B1.a = PeekA(*p+1)
    B2.a = PeekA(*p+2)
    B3.a = PeekA(*p+3)
   
    ProcedureReturn U32V(B0 | B1 << 8 | B2 << 16 | B3 << 24)
  EndProcedure
 
  Procedure.q Addition(VarA.q, VarB.q, VarC.q = -1)
   
    Result.q = U32V(VarA + VarB)
   
    If VarC >= 0
      Result = U32V(Result + VarC)
    EndIf
   
    ProcedureReturn Result
  EndProcedure
 
  Procedure.q RABBIT_GFunc(x.q)
   
    x * x
   
    ProcedureReturn U32V(x ! (x >> 32))
  EndProcedure
 
  Procedure RABBIT_NextState128(*Rabbit.Rabbit128)
   
    ; Temporary variables
    Protected Temp.Temp128, Index.l
   
    ; Save old counter values
    For Index = 0 To 7
      Temp\OldC[Index] = *Rabbit\C[Index]
    Next
   
    ; Calculate new counter values
    *Rabbit\C[0] = Addition(*Rabbit\C[0], $4D34D34D + *Rabbit\Carry)
    *Rabbit\C[1] = Addition(*Rabbit\C[1], $D34D34D3 + Bool(*Rabbit\C[0] < Temp\OldC[0]))
    *Rabbit\C[2] = Addition(*Rabbit\C[2], $34D34D34 + Bool(*Rabbit\C[1] < Temp\OldC[1]))
    *Rabbit\C[3] = Addition(*Rabbit\C[3], $4D34D34D + Bool(*Rabbit\C[2] < Temp\OldC[2]))
   
    *Rabbit\C[4] = Addition(*Rabbit\C[4], $D34D34D3 + Bool(*Rabbit\C[3] < Temp\OldC[3]))
    *Rabbit\C[5] = Addition(*Rabbit\C[5], $34D34D34 + Bool(*Rabbit\C[4] < Temp\OldC[4]))
    *Rabbit\C[6] = Addition(*Rabbit\C[6], $4D34D34D + Bool(*Rabbit\C[5] < Temp\OldC[5]))
    *Rabbit\C[7] = Addition(*Rabbit\C[7], $D34D34D3 + Bool(*Rabbit\C[6] < Temp\OldC[6]))
   
    *Rabbit\Carry = Bool(*Rabbit\C[7] < Temp\OldC[7])
   
    ; Calculate the g-values
   
    For Index = 0 To 7
      Temp\g[Index] = RABBIT_GFunc(Addition(*Rabbit\X[Index], *Rabbit\C[Index]))
    Next
   
    ; Calculate new state values
   
    *Rabbit\X[0] = Addition(Temp\g[0], ROTL32(Temp\g[7],16), ROTL32(Temp\g[6], 16))
    *Rabbit\X[1] = Addition(Temp\g[1], ROTL32(Temp\g[0], 8), Temp\g[7])
    *Rabbit\X[2] = Addition(Temp\g[2], ROTL32(Temp\g[1],16), ROTL32(Temp\g[0], 16))
    *Rabbit\X[3] = Addition(Temp\g[3], ROTL32(Temp\g[2], 8), Temp\g[1])
    *Rabbit\X[4] = Addition(Temp\g[4], ROTL32(Temp\g[3],16), ROTL32(Temp\g[2], 16))
    *Rabbit\X[5] = Addition(Temp\g[5], ROTL32(Temp\g[4], 8), Temp\g[3])
    *Rabbit\X[6] = Addition(Temp\g[6], ROTL32(Temp\g[5],16), ROTL32(Temp\g[4], 16))
    *Rabbit\X[7] = Addition(Temp\g[7], ROTL32(Temp\g[6], 8), Temp\g[5])
   
  EndProcedure

  Procedure RABBIT_KeySetup128(*Core.Core128, *Key)
   
    ; Temporary Variables
    Protected k0.q, k1.q, k2.q, k3.q, Index.l
   
    ; Generate four subkeys
    k0 = U8TO32_LITTLE(*Key + 0)
    k1 = U8TO32_LITTLE(*Key + 4)
    k2 = U8TO32_LITTLE(*Key + 8)
    k3 = U8TO32_LITTLE(*Key + 12)
   
    ; Generate initial state variables
    *Core\Master\X[0] = k0
    *Core\Master\X[2] = k1
    *Core\Master\X[4] = k2
    *Core\Master\X[6] = k3
    *Core\Master\X[1] = U32V(k3 << 16) | (k2 >> 16)
    *Core\Master\X[3] = U32V(k0 << 16) | (k3 >> 16)
    *Core\Master\X[5] = U32V(k1 << 16) | (k0 >> 16)
    *Core\Master\X[7] = U32V(k2 << 16) | (k1 >> 16)
   
    ; Generate initial counter values
    *Core\Master\C[0] = ROTL32(k2, 16)
    *Core\Master\C[2] = ROTL32(k3, 16)
    *Core\Master\C[4] = ROTL32(k0, 16)
    *Core\Master\C[6] = ROTL32(k1, 16)
   
    *Core\Master\C[1] = (k0 & $FFFF0000) | (k1 & $FFFF)
    *Core\Master\C[3] = (k1 & $FFFF0000) | (k2 & $FFFF)
    *Core\Master\C[5] = (k2 & $FFFF0000) | (k3 & $FFFF)
    *Core\Master\C[7] = (k3 & $FFFF0000) | (k0 & $FFFF)
   
    *Core\Master\Carry = 0
   
    ; Iterate the system four times
   
    For index = 0 To 3
      RABBIT_NextState128(*Core\Master)
    Next
   
    ; Modify the counters
    For Index = 0 To 7
      *Core\Master\C[Index] ! *Core\Master\X[(Index + 4) & 7]
    Next
   
    ; Copy master instance to work instance
   
    For Index = 0 To 7
      *Core\Work\X[Index] = *Core\Master\X[Index]
      *Core\Work\C[Index] = *Core\Master\C[Index]
    Next
   
    *Core\Work\Carry = *Core\Master\Carry
   
  EndProcedure
 
  Procedure RABBIT_InitVectorSetup128(*Core.Core128, *InitVector)
   
    ; Temporary variables
    Protected i0.q, i1.q, i2.q, i3.q, Index.l
   
    ; Generate four subvectors
    i0 = U8TO32_LITTLE(*InitVector + 0)
    i2 = U8TO32_LITTLE(*InitVector + 4)
    i1 = (i0 >> 16) | (i2 & $FFFF0000)
    i3 = (i2 << 16) | (i0 & $0000FFFF)
   
    ; Modify counter values
   
    *Core\Work\C[0] = *Core\Master\C[0] ! i0
    *Core\Work\C[1] = *Core\Master\C[1] ! i1
    *Core\Work\C[2] = *Core\Master\C[2] ! i2
    *Core\Work\C[3] = *Core\Master\C[3] ! i3
   
    *Core\Work\C[4] = *Core\Master\C[4] ! i0
    *Core\Work\C[5] = *Core\Master\C[5] ! i1
    *Core\Work\C[6] = *Core\Master\C[6] ! i2
    *Core\Work\C[7] = *Core\Master\C[7] ! i3
   
    ; Copy state variables
   
    For Index = 0 To 7
      *Core\Work\X[Index] = *Core\Master\X[Index]
    Next
   
    *Core\Work\Carry = *Core\Master\Carry
   
    ; Iterate the system four times
   
    For index = 0 To 3
      RABBIT_NextState128(*Core\Work)
    Next
   
  EndProcedure

  Procedure RABBIT_Process_Bytes128(*Core.Core128, *Input, *Output, MsgLen.l)
   
    ; Temporary variables
   
    Protected Buffer.Buffer128, Index.l
   
    ; Encrypt/decrypt all full blocks
   
    While MsgLen >= 16
     
      ; Iterate the system
      RABBIT_NextState128(*Core\Work)
     
      ; Encrypt/decrypt 16 bytes of data
      PokeU32(*Output + 00, PeekU32(*Input + 00) ! *Core\Work\X[0] ! (*Core\Work\X[5] >> 16) ! U32V(*Core\Work\X[3] << 16))
      PokeU32(*Output + 04, PeekU32(*Input + 04) ! *Core\Work\X[2] ! (*Core\Work\X[7] >> 16) ! U32V(*Core\Work\X[5] << 16))
      PokeU32(*Output + 08, PeekU32(*Input + 08) ! *Core\Work\X[4] ! (*Core\Work\X[1] >> 16) ! U32V(*Core\Work\X[7] << 16))
      PokeU32(*Output + 12, PeekU32(*Input + 12) ! *Core\Work\X[6] ! (*Core\Work\X[3] >> 16) ! U32V(*Core\Work\X[1] << 16))
     
      *Input + 16
      *Output + 16
      MsgLen - 16
     
    Wend
   
    ; Encrypt/decrypt remaining data
   
    If MsgLen <> 0
     
      ; Iterate the system
      RABBIT_NextState128(*Core\Work)
     
      ; Generate 16 bytes of pseudo-random data */
     
      PokeU32(@Buffer + 00, *Core\Work\X[0] ! (*Core\Work\X[5]>>16) ! U32V(*Core\Work\X[3]<<16))
      PokeU32(@Buffer + 04, *Core\Work\X[2] ! (*Core\Work\X[7]>>16) ! U32V(*Core\Work\X[5]<<16))
      PokeU32(@Buffer + 06, *Core\Work\X[4] ! (*Core\Work\X[1]>>16) ! U32V(*Core\Work\X[7]<<16))
      PokeU32(@Buffer + 12, *Core\Work\X[6] ! (*Core\Work\X[3]>>16) ! U32V(*Core\Work\X[1]<<16))
     
      For Index = 0 To MsgLen - 1
        PokeA(*Output, PeekA(*Input) ! Buffer\Buffer[Index])
        *Output + 1
        *Input + 1
      Next
     
    EndIf
   
  EndProcedure

  Procedure RABBIT_Encrypt(*This.Private_Members, *PlainText, *CipheredText, StringByteLength.l)
   
    NormKey.s = Normalizer(*This\Key, 128)
    RABBIT_KeySetup128(Core128.Core128, @NormKey)
   
    If *This\InitVector <> "NULL"
      NormInitVec.s = Normalizer(*This\InitVector, 64)
      RABBIT_InitVectorSetup128(Core128, @NormInitVec)
    EndIf
   
    RABBIT_Process_Bytes128(Core128, *PlainText, *CipheredText, StringByteLength)
   
  EndProcedure
 
  Procedure RABBIT_Decrypt(*This.Private_Members, *PlainText, *CipheredText, StringByteLength.l)
   
    NormKey.s = Normalizer(*This\Key, 128)
    RABBIT_KeySetup128(Core128.Core128, @NormKey)
   
    If *This\InitVector <> "NULL"
      NormInitVec.s = Normalizer(*This\InitVector, 64)
      RABBIT_InitVectorSetup128(Core128, @NormInitVec)
    EndIf
   
    RABBIT_Process_Bytes128(Core128, *CipheredText, *PlainText, StringByteLength)
   
  EndProcedure
 
  ; <<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Getters <<<<<

  Procedure.s GetKey(*This.Private_Members)
   
    ProcedureReturn *This\Key
  EndProcedure
 
  Procedure.s GetInitVector(*This.Private_Members)
   
    ProcedureReturn *This\InitVector
  EndProcedure
 
  ; <<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Setters <<<<<

  Procedure SetKey(*This.Private_Members, P_Key.s)
   
    If P_Key <> ""
      *This\Key = P_Key
    Else
      *This\Key = "RabbitCipher"
    EndIf
   
  EndProcedure
 
  Procedure SetInitVector(*This.Private_Members, P_InitVector.s)
   
    If P_InitVector <> ""
      *This\InitVector = P_InitVector
    Else
      *This\InitVector = "InitVector"
    EndIf
   
  EndProcedure
 
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Write on file operators <<<<<
 
  Procedure RC_WriteString(*This.Private_Members, FileID.i, P_String.s)

    StringMemorySize.q = StringByteLength(P_String) + SizeOf(Character)
    WriteU32(FileID, StringMemorySize)
   
    *CipheredText = AllocateMemory(StringMemorySize)
    RABBIT_Encrypt(*This, @P_String, *CipheredText, StringByteLength(P_String))
    WriteData(FileID, *CipheredText, StringMemorySize)
   
    FreeMemory(*CipheredText)
   
  EndProcedure
 
  Procedure RC_WriteByte(*This.Private_Members, FileID.i, P_Value.b)
   
    If P_Value < 0
      Sign.s = "-"
      P_Value = P_Value * -1
    EndIf
   
    RC_WriteString(*This, FileID, Sign + RSet(Str(P_Value), 6, "0"))
   
  EndProcedure
 
  Procedure RC_WriteAsciiCharacter(*This.Private_Members, FileID.i, P_Value.a)
   
    RC_WriteString(*This, FileID, RSet(Str(P_Value), 6, "0"))
   
  EndProcedure
 
  Procedure RC_WriteWord(*This.Private_Members, FileID.i, P_Value.w)
   
    If P_Value < 0
      Sign.s = "-"
      P_Value = P_Value * -1
    EndIf
   
    RC_WriteString(*This, FileID, Sign + RSet(Str(P_Value), 10, "0"))
   
  EndProcedure
 
  Procedure RC_WriteUnicodeCharacter(*This.Private_Members, FileID.i, P_Value.u)
   
    RC_WriteString(*This, FileID, RSet(Str(P_Value), 10, "0"))
   
  EndProcedure
 
  Procedure RC_WriteCharacter(*This.Private_Members, FileID.i, P_Value.c)
   
    RC_WriteString(*This, FileID, RSet(Str(P_Value), 10, "0"))
   
  EndProcedure
 
  Procedure RC_WriteLong(*This.Private_Members, FileID.i, P_Value.l)
   
    If P_Value < 0
      Sign.s = "-"
      P_Value = P_Value * -1
    EndIf
   
    RC_WriteString(*This, FileID, Sign + RSet(Str(P_Value), 22, "0"))
   
  EndProcedure
 
  Procedure RC_WriteQuad(*This.Private_Members, FileID.i, P_Value.q)
   
    If P_Value < 0
      Sign.s = "-"
      P_Value = P_Value * -1
    EndIf
   
    RC_WriteString(*This, FileID, Sign + RSet(Str(P_Value), 42, "0"))
   
  EndProcedure
 
  Procedure RC_WriteInteger(*This.Private_Members, FileID.i, P_Value.i)
   
    If P_Value < 0
      Sign.s = "-"
      P_Value = P_Value * -1
    EndIf
   
    RC_WriteString(*This, FileID, Sign + RSet(Str(P_Value), 42, "0"))
   
  EndProcedure
 
  Procedure RC_WriteFloat(*This.Private_Members, FileID.i, P_Value.f)
   
    RC_WriteString(*This, FileID, StrF(P_Value, 14))
   
  EndProcedure
 
  Procedure RC_WriteDouble(*This.Private_Members, FileID.i, P_Value.d)
   
    RC_WriteString(*This, FileID, StrD(P_Value, 25))
   
  EndProcedure

  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Read on file operators <<<<<
 
  Procedure.s RC_ReadString(*This.Private_Members, FileID.i)

    StringMemorySize.q = ReadU32(FileID)
    *PlainText = AllocateMemory(StringMemorySize)
    *CipheredText = AllocateMemory(StringMemorySize)
   
    ReadData(FileID, *CipheredText, StringMemorySize)
   
    RABBIT_Decrypt(*This, *PlainText, *CipheredText, StringMemorySize - SizeOf(Character))
    DecryptedString.s = PeekS(*PlainText)
   
    FreeMemory(*PlainText)
    FreeMemory(*CipheredText)
   
    ProcedureReturn DecryptedString
  EndProcedure
 
  Procedure.b RC_ReadByte(*This.Private_Members, FileID.i)
   
    ProcedureReturn Val(RC_ReadString(*This, FileID))
  EndProcedure
 
  Procedure.a RC_ReadAsciiCharacter(*This.Private_Members, FileID.i)
   
    ProcedureReturn Val(RC_ReadString(*This, FileID))
  EndProcedure
 
  Procedure.w RC_ReadWord(*This.Private_Members, FileID.i)
   
    ProcedureReturn Val(RC_ReadString(*This, FileID))
  EndProcedure
 
  Procedure.u RC_ReadUnicodeCharacter(*This.Private_Members, FileID.i)
   
    ProcedureReturn Val(RC_ReadString(*This, FileID))
  EndProcedure
 
  Procedure.c RC_ReadCharacter(*This.Private_Members, FileID.i)
   
    ProcedureReturn Val(RC_ReadString(*This, FileID))
  EndProcedure
 
  Procedure.l RC_ReadLong(*This.Private_Members, FileID.i)
   
    ProcedureReturn Val(RC_ReadString(*This, FileID))
  EndProcedure
 
  Procedure.q RC_ReadQuad(*This.Private_Members, FileID.i)
   
    ProcedureReturn Val(RC_ReadString(*This, FileID))
  EndProcedure
 
  Procedure.i RC_ReadInteger(*This.Private_Members, FileID.i)
   
    ProcedureReturn Val(RC_ReadString(*This, FileID))
  EndProcedure
 
  Procedure.f RC_ReadFloat(*This.Private_Members, FileID.i)
   
    ProcedureReturn ValF(RC_ReadString(*This, FileID))
  EndProcedure
 
  Procedure.d RC_ReadDouble(*This.Private_Members, FileID.i)
   
    ProcedureReturn ValD(RC_ReadString(*This, FileID))
  EndProcedure
 
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Destructor <<<<<

  Procedure Free(*This.Private_Members)
   
    FreeStructure(*This)
   
  EndProcedure
 
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Constructor <<<<<

  Procedure.i New(P_Key.s = "RabbitCipher", P_InitVector.s = "InitVector")
   
    *This.Private_Members = AllocateStructure(Private_Members)
    *This\VirtualTable = ?START_METHODS
   
    SetKey(*This, P_Key)
    SetInitVector(*This, P_InitVector)
   
    ProcedureReturn *This
  EndProcedure
 
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Virtual Table Entries <<<<<

  DataSection
    START_METHODS:
    Data.i @GetKey()
    Data.i @GetInitVector()
    Data.i @SetKey()
    Data.i @SetInitVector()
    Data.i @RC_WriteString()
    Data.i @RC_WriteByte()
    Data.i @RC_WriteAsciiCharacter()
    Data.i @RC_WriteWord()
    Data.i @RC_WriteUnicodeCharacter()
    Data.i @RC_WriteCharacter()
    Data.i @RC_WriteLong()
    Data.i @RC_WriteQuad()
    Data.i @RC_WriteInteger()
    Data.i @RC_WriteFloat()
    Data.i @RC_WriteDouble()
    Data.i @RC_ReadString()
    Data.i @RC_ReadByte()
    Data.i @RC_ReadAsciiCharacter()
    Data.i @RC_ReadWord()
    Data.i @RC_ReadUnicodeCharacter()
    Data.i @RC_ReadCharacter()
    Data.i @RC_ReadLong()
    Data.i @RC_ReadQuad()
    Data.i @RC_ReadInteger()
    Data.i @RC_ReadFloat()
    Data.i @RC_ReadDouble()
    Data.i @Free()
    END_METHODS:
  EndDataSection
 
EndModule

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< Code generated in : 00.001 seconds (96000.00 lines/second) <<<<<
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

CompilerIf #PB_Compiler_IsMainFile
 
  UseMD5Fingerprint()
  RC.RabbitCipher::RabbitCipher = RabbitCipher::New()
 
  Varw.w = 32700
  Varl.l = -2147483645
  Varq.q = 9223372036854775800
  Varf.f = 2 * #PI
  Vard.d = 3 * #PI
  Text.s = "J'aime les déesses nordiques super sexy !"
 
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test on file"
  Debug ""
  Debug "Original : "
 
  Debug Varw
  Debug Varl
  Debug Varq
  Debug Varf
  Debug Vard
  Debug Text
  Debug ""
 
  If CreateFile(0, "Test.rc")
   
    RC\SetKey("PureBasic 5.72") ; Set the key
    RC\SetInitVector("") ; Restore the default Init vector
   
    RC\RC_WriteWord(0, Varw)
    RC\RC_WriteLong(0, Varl) 
    RC\RC_WriteQuad(0, Varq)
   
    RC\SetKey("") ; Restore the default key
    RC\SetInitVector("NULL") ; No Init vector here
   
    RC\RC_WriteFloat(0, Varf)
    RC\RC_WriteDouble(0, Vard)
    RC\RC_WriteString(0, Text)
   
    CloseFile(0)
   
  EndIf
 
  Debug "FileSize : " + Str(FileSize("Test.rc"))
  Debug "From the file : "
 
  If ReadFile(1, "Test.rc")
   
    RC\SetKey("PureBasic 5.72") ; Set the key
    RC\SetInitVector("") ; Restore the default Init vector
   
    Debug RC\RC_ReadWord(1)
    Debug RC\RC_ReadLong(1)
    Debug RC\RC_ReadQuad(1)
   
    RC\SetKey("") ; Restore the default key
    RC\SetInitVector("NULL")  ; No Init vector here
   
    Debug RC\RC_ReadFloat(1)
    Debug RC\RC_ReadDouble(1)
    Debug RC\RC_ReadString(1)
   
    CloseFile(1)
    DeleteFile("Test.rc")
   
  EndIf
 
  RC\Free()
 
CompilerEndIf

; <<<<<<<<<<<<<<<<<<<<<<<
; <<<<< END OF FILE <<<<<
; <<<<<<<<<<<<<<<<<<<<<<<

_________________
The Stone Age did not end due to a shortage of stones !


Top
 Profile  
Reply with quote  
 Post subject: Re: Rabbit Cipher - Module
PostPosted: Mon Nov 09, 2020 3:07 pm 
Offline
Enthusiast
Enthusiast
User avatar

Joined: Sun Apr 05, 2020 11:28 am
Posts: 518
Location: Pandora
Hi, you might want to explain the way it works a bit more, otherwise hardly any of the people will use it.
It is also important to explain what happens if you encrypt twice with the same IV and key, otherwise it is a trap.
And how to create the key and IV correctly.
And how to encrypt very large files in blocks with progress.
What to do with the IV and why it is extremely important in this type of crypters to ensure the integrity of a decrypted file.

Primarily this is a very good thing and a good replacement for PB AES, a light version that is extremely easy to use.

Best Regards Saki

_________________
地球上の平和


Top
 Profile  
Reply with quote  
 Post subject: Re: Rabbit Cipher - Module
PostPosted: Mon Nov 09, 2020 4:30 pm 
Offline
Enthusiast
Enthusiast
User avatar

Joined: Sun Jul 07, 2013 11:35 am
Posts: 587
Location: Canada
Saki wrote:
Hi, you might want to explain the way it works a bit more, otherwise hardly any of the people will use it.

I'm still searching ways to improve my hacking sessions for improvement.
Saki wrote:
It is also important to explain what happens if you encrypt twice with the same IV and key, otherwise it is a trap.

I'm not sure about that.
Saki wrote:
And how to create the key and IV correctly.

I 'm still working on that aspect. The current way of generating Key and IV for those of you have their alphabet coded between character 32 to 255, the key and init vector are created like this :

000 Value 000 value 000 value 000 ...

it's not an invalid Key or Init Vector they are part of their respective spaces 2^128 keys possible and 2^64 Init Vectors possible but I don't like that. If someone has a better solution for the "Normalizer()" procedure I will be glad to integrate it. But some of you will probably prefer to put Keys and Init Vectors created with a Crypto random generator into DataSection inside their programs. So at this point it's a preference and a design choice. Use your imagination to modify my code to fit your needs.
Saki wrote:
And how to encrypt very large files in blocks with progress.

To do that you need to work with thread, count how many block with the given file size, and a counter inside the Process_Byte procedure and compare the two. So the design has to be reviewed for that.
Saki wrote:
What to do with the IV and why it is extremely important in this type of crypters to ensure the integrity of a decrypted file.

I'm not an expert in Cryptographic algorithm at all. It's probably best to read this document : https://www.ecrypt.eu.org/stream/p3ciphers/rabbit/rabbit_p3.pdf
Saki wrote:
Primarily this is a very good thing and a good replacement for PB AES, a light version that is extremely easy to use.

What I don't like about AES is the fact that short strings can't be ciphered without padding them. It's a real pain.

To make a long story short, some work has to be done and it will require more time and research to solve the remaining issues.

Best regards
StarBootics

_________________
The Stone Age did not end due to a shortage of stones !


Top
 Profile  
Reply with quote  
 Post subject: Re: Rabbit Cipher - Module
PostPosted: Fri Nov 13, 2020 6:55 am 
Offline
PureBasic Expert
PureBasic Expert

Joined: Sun Aug 08, 2004 5:21 am
Posts: 3712
Location: Netherlands
StarBootics wrote:
If someone has a better solution for the "Normalizer()" procedure I will be glad to integrate it.

When I searched on the internet for password hashing, algorithms like PBKDF2 or Argon2 came up.
For PBKDF2 there already seems to be a PureBasic module on the German forum.
I don't have much knowledge about this myself. Personally I might even use something like a FNV hash but that probably isn't very secure.

Saki wrote:
And how to encrypt very large files in blocks with progress.

I tried and a buffer of 128KiB seems to work very good.
Tracking progress could be done with a callback procedure or posting events.
What seems difficult to me is for example if you allow the input file to be overwritten or not. :?

_________________
macOS 10.15 Catalina, Windows 10


Top
 Profile  
Reply with quote  
 Post subject: Re: Rabbit Cipher - Module
PostPosted: Fri Nov 13, 2020 2:26 pm 
Offline
Enthusiast
Enthusiast
User avatar

Joined: Sun Apr 05, 2020 11:28 am
Posts: 518
Location: Pandora
Hi,
some text about it.

It is sufficient to specify a source and a destination address, and to specify the bytes to be encrypted.

A File or String Crypter should be created as a separate module.

The IV is usually added before or after the data.

Also, the Rabbit Algorytmus is really well suited to support the AES implementation of PB with a
easy to handle alternative to be added.
I am not aware that it was broken.
Primarily attacks on the password are the weak point.

There is nothing to be said against generating a hash from a SHA3 hash by iteration,
whereby a salt can be processed as well.

The established procedures for key generation are supposed to slow down the key calculation
and complicate the implementation in hardware.

With the advancing development of computer technology, these procedures are increasingly
ineffektive.

A SHA3 Hash with an appropriate salt, or a pass phrase and 1e5 iterations you are quickly beyond all imaginable efforts.
Always finalize the iterations of key generation and checksum generating.

With the blockwise transfer you can, after defining the procedure, as well as with the key generation
can also be proceeded differently.
If you set the protocol you can also set the first 8 bytes of the first encrypted block
as IV for the second block to be encrypted, etc.
This corresponds to the CBC mode.

Yes, the input file is usually overwritten directly.

It always depends on what you want.
If the writing process breaks off for some reason when you overwrite directly, it is not good.
To encrypt disks but always like this.

Everything that is temporarily unencrypted is a problem.
But with SSD this is a bit different.
A new write operation uses a new block.
If no Trim is executed in the meantime, the data remains as a shadow.
This is all very complex.

The read and write accesses are fastest if you do not go below 16384 (4096*4) bytes for the blocks, but only for mechanical disks.
More than 16384 does almost nothing.
The progress is shown with a timer, about 30 > 100 ms, then it does not brake, faster 100 looks better.

An encrypted file must always have a checksum, in fact a crypt hash.
Otherwise small errors are not noticed or the files can be manipulated unnoticed.
Because reading and writing is the same, other problems can occur.
Encrypted data can be marked with a Crypt marker.
Primarily a row of zeros or spaces at the end is enough, because something like this can not occur in an encrypted file.
The encrypted files may only consist of random data without any recognizable header or extender.

Best Regards Saki

_________________
地球上の平和


Top
 Profile  
Reply with quote  
 Post subject: Re: Rabbit Cipher - Module
PostPosted: Fri Nov 13, 2020 2:49 pm 
Offline
PureBasic Expert
PureBasic Expert

Joined: Sun Aug 08, 2004 5:21 am
Posts: 3712
Location: Netherlands
Thanks for the explanation Saki.
It makes me realize that there's more to it then I thought which I have little or no knowledge about.
So I'll leave my asm based Rabbit module posted in this thread as it is; capable of processing a block of memory like you mentioned.
I did do a speed comparison with the PureBasic AESEncoder command.
On my computer the Rabbit cipher was about 4 times faster for a large block of memory but I don't know if PB makes use of hardware AES support modern processors offer.

_________________
macOS 10.15 Catalina, Windows 10


Top
 Profile  
Reply with quote  
 Post subject: Re: Rabbit Cipher - Module
PostPosted: Fri Nov 13, 2020 2:54 pm 
Offline
Enthusiast
Enthusiast
User avatar

Joined: Sun Apr 05, 2020 11:28 am
Posts: 518
Location: Pandora
Hi Wilbert,
PB use only Software AES.
Your Module is perfect, i like it !

Best Regards Saki

_________________
地球上の平和


Top
 Profile  
Reply with quote  
 Post subject: Re: Rabbit Cipher - Module
PostPosted: Mon Nov 16, 2020 9:13 pm 
Offline
Enthusiast
Enthusiast
User avatar

Joined: Sun Apr 05, 2020 11:28 am
Posts: 518
Location: Pandora
File crypter with automatically randomized IV, progressbar and blockwise CBC crypting added.

Damn fast :twisted:

https://www.purebasic.fr/english/viewtopic.php?f=27&t=76286

Best Regards Saki

_________________
地球上の平和


Top
 Profile  
Reply with quote  
 Post subject: Re: Rabbit Cipher - Module
PostPosted: Fri Nov 20, 2020 2:59 am 
Offline
Enthusiast
Enthusiast
User avatar

Joined: Sun Jul 07, 2013 11:35 am
Posts: 587
Location: Canada
Hello everyone,

After a deep review I have finally came up with a better solution for the Normalizer() procedure. Also I have discovered a problem when counter system was reset at every information written in the file. According to the documentation the Rabbit cipher was design to cipher 2^64 blocks of 16 bytes each without any reset. So let's do some math here :

2^64 -> 18 446 744 073 709 551 616 blocks of 16 bytes each -> 295 147 905 179 352 825 856 bytes -> 1 099 511 627 776 Tera-bytes

Now the setup will be done by the constructor automatically and it has to be done manually when the Key or the InitVector or both changes. I have also optimize the Addition() procedure to be much faster. Finally I have added a RC_WriteData() and RC_ReadData() methods to the mix so now you can cipher data if needed (see the example).

So without any further due, this is the version 2.0.0 of the convenient Read/Write on file library.

Code:
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; AUTOMATICALLY GENERATED CODE, DO NOT MODIFY
; UNLESS YOU REALLY, REALLY, REALLY MEAN IT !!
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; Code generated by : Dev-Object - V1.2.0
; Project name : Read Write RabbitCipher
; File name : Read Write RabbitCipher 128 - OOP.pb
; File Version : 2.0.0
; Programmation : OK
; Programmed by : StarBootics
; Creation Date : Noverber 8th, 2020
; Last update : November 19th, 2020
; Coded for PureBasic : V5.73 beta 4
; Platform : Windows, Linux, MacOS X
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; Programming notes
;
; 1. Rabbit was designed by Martin Boesgaard, Mette Vesterager,
;    Thomas Pedersen, Jesper Christiansen and Ove Scavenius.
;
;    https://www.ecrypt.eu.org/stream/rabbitpf.html
;
; 2. Type of Algorithm : Synchronous Stream Cipher
;
; 3. Rabbit has been released into the public domain and may
;    be used freely for any purpose.
;
; 4. I deserve credit only for porting Rabbit Cipher from C to
;    PureBasic. I'm not the original designer of the algorithm
;    so no credit to me for that.
;
; 5. The software is provided "as is" without any express or
;    implied warranty. You are using it at your own risk. The
;    original authors and/or me shall not in any way be liable
;    for any use of this software.
;
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

DeclareModule RabbitCipher

  Interface RabbitCipher
   
    GetKey.s()
    GetInitVector.s()
    SetKey(P_Key.s)
    SetInitVector(P_InitVector.s)
    RunSetup()
   
    RC_WriteString(FileID.i, P_String.s)
    RC_WriteByte(FileID.i, P_Value.b)
    RC_WriteAsciiCharacter(FileID.i, P_Value.a)
    RC_WriteWord(FileID.i, P_Value.w)
    RC_WriteUnicodeCharacter(FileID.i, P_Value.u)
    RC_WriteCharacter(FileID.i, P_Value.c)
    RC_WriteLong(FileID.i, P_Value.l)
    RC_WriteQuad(FileID.i, P_Value.q)
    RC_WriteInteger(FileID.i, P_Value.i)
    RC_WriteFloat(FileID.i, P_Value.f)
    RC_WriteDouble(FileID.i, P_Value.d)
    RC_WriteData(FileID.i, *Memory, Size.l)
   
    RC_ReadString.s(FileID.i)
    RC_ReadByte.b(FileID.i)
    RC_ReadAsciiCharacter.a(FileID.i)
    RC_ReadWord.w(FileID.i)
    RC_ReadUnicodeCharacter.u(FileID.i)
    RC_ReadCharacter.c(FileID.i)
    RC_ReadLong.l(FileID.i)
    RC_ReadQuad.q(FileID.i)
    RC_ReadInteger.i(FileID.i)
    RC_ReadFloat.f(FileID.i)
    RC_ReadDouble.d(FileID.i)
    RC_ReadData(FileID.i, *Memory, Size.l)
   
    Free()
   
  EndInterface
 
  Declare.i New(P_Key.s = "RabbitCipher", P_InitVector.s = "InitVector")
 
EndDeclareModule

Module RabbitCipher
 
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Structures declaration <<<<<
 
  Structure Rabbit
   
    X.q[8]
    C.q[8]
    Carry.q
   
  EndStructure
 
  Structure Temp
   
    g.q[8]
    OldC.q[8]
   
  EndStructure
 
  Structure Buffer
   
    Buffer.a[16]
   
  EndStructure
 
  Structure Core
   
    Master.Rabbit
    Work.Rabbit
   
  EndStructure
 
  Structure Private_Members
   
    VirtualTable.i
    Key.s
    InitVector.s
    IsSetupDone.b
    Core.Core
   
  EndStructure

  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Macros declaration <<<<<
 
  Macro U32V(v)
   
    ((v) & $FFFFFFFF)
   
  EndMacro
 
  Macro ROTL32(v, n)
   
    (U32V((v) << (n)) | ((v) >> (32 - (n))))
   
  EndMacro
 
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Procedures declaration (Private) <<<<<
 
  Procedure.i Normalizer(Input.s, BitsLength.l)
   
    Byte = BitsLength >> 3
   
    Output.s = StringFingerprint(Input, #PB_Cipher_MD5)
   
    *Normalized = AllocateMemory(Byte)
    *Cursor = *Normalized
   
    For Index = 1 To Byte
     
      PokeA(*Cursor, Val("$" + Mid(Output, Index, 2)))
      *Cursor + 1
     
    Next
   
    ProcedureReturn *Normalized
  EndProcedure
 
  Procedure.q PeekU32(*Buffer)
   
    ; Even if a quad size is 64-bit, we are
    ; interested only by the first 32-bit.
   
    CopyMemory(*Buffer, @Var.q, 4)
   
    ProcedureReturn Var
  EndProcedure
 
  Procedure PokeU32(*Buffer, Var.q)
   
    ; Even if a quad size is 64-bit, we are
    ; interested only by the first 32-bit.
   
    CopyMemory(@Var, *Buffer, 4)
   
  EndProcedure
 
  Procedure.q ReadU32(FileID.i)
   
    ReadData(FileID, @Var.q, 4)
   
    ProcedureReturn Var
  EndProcedure
 
  Procedure WriteU32(FileID.i, Var.q)
   
    WriteData(FileID, @Var, 4)
   
  EndProcedure
 
  Procedure.q U8TO32_LITTLE(*p)
   
    B0.a = PeekA(*p+0)
    B1.a = PeekA(*p+1)
    B2.a = PeekA(*p+2)
    B3.a = PeekA(*p+3)
   
    ProcedureReturn U32V(B0 | B1 << 8 | B2 << 16 | B3 << 24)
  EndProcedure
 
  Procedure.q Addition(VarA.q, VarB.q, VarC.q = 0)
   
    Result.q = U32V(VarA + VarB)
    Result = U32V(Result + VarC)
   
    ProcedureReturn Result
  EndProcedure
 
  Procedure.q RABBIT_GFunc(x.q)
   
    x * x
   
    ProcedureReturn U32V(x ! (x >> 32))
  EndProcedure
 
  Procedure RABBIT_NextState128(*Rabbit.Rabbit)
   
    ; Temporary variables
    Protected Temp.Temp, Index.l
   
    ; Save old counter values
    For Index = 0 To 7
      Temp\OldC[Index] = *Rabbit\C[Index]
    Next
   
    ; Calculate new counter values
    *Rabbit\C[0] = Addition(*Rabbit\C[0], $4D34D34D + *Rabbit\Carry)
    *Rabbit\C[1] = Addition(*Rabbit\C[1], $D34D34D3 + Bool(*Rabbit\C[0] < Temp\OldC[0]))
    *Rabbit\C[2] = Addition(*Rabbit\C[2], $34D34D34 + Bool(*Rabbit\C[1] < Temp\OldC[1]))
    *Rabbit\C[3] = Addition(*Rabbit\C[3], $4D34D34D + Bool(*Rabbit\C[2] < Temp\OldC[2]))
   
    *Rabbit\C[4] = Addition(*Rabbit\C[4], $D34D34D3 + Bool(*Rabbit\C[3] < Temp\OldC[3]))
    *Rabbit\C[5] = Addition(*Rabbit\C[5], $34D34D34 + Bool(*Rabbit\C[4] < Temp\OldC[4]))
    *Rabbit\C[6] = Addition(*Rabbit\C[6], $4D34D34D + Bool(*Rabbit\C[5] < Temp\OldC[5]))
    *Rabbit\C[7] = Addition(*Rabbit\C[7], $D34D34D3 + Bool(*Rabbit\C[6] < Temp\OldC[6]))
   
    *Rabbit\Carry = Bool(*Rabbit\C[7] < Temp\OldC[7])
   
    ; Calculate the g-values
   
    For Index = 0 To 7
      Temp\g[Index] = RABBIT_GFunc(Addition(*Rabbit\X[Index], *Rabbit\C[Index]))
    Next
   
    ; Calculate new state values
   
    *Rabbit\X[0] = Addition(Temp\g[0], ROTL32(Temp\g[7],16), ROTL32(Temp\g[6], 16))
    *Rabbit\X[1] = Addition(Temp\g[1], ROTL32(Temp\g[0], 8), Temp\g[7])
    *Rabbit\X[2] = Addition(Temp\g[2], ROTL32(Temp\g[1],16), ROTL32(Temp\g[0], 16))
    *Rabbit\X[3] = Addition(Temp\g[3], ROTL32(Temp\g[2], 8), Temp\g[1])
    *Rabbit\X[4] = Addition(Temp\g[4], ROTL32(Temp\g[3],16), ROTL32(Temp\g[2], 16))
    *Rabbit\X[5] = Addition(Temp\g[5], ROTL32(Temp\g[4], 8), Temp\g[3])
    *Rabbit\X[6] = Addition(Temp\g[6], ROTL32(Temp\g[5],16), ROTL32(Temp\g[4], 16))
    *Rabbit\X[7] = Addition(Temp\g[7], ROTL32(Temp\g[6], 8), Temp\g[5])
   
  EndProcedure

  Procedure RABBIT_KeySetup128(*Core.Core, *Key)
   
    ; Temporary Variables
    Protected k0.q, k1.q, k2.q, k3.q, Index.l
   
    ; Generate four subkeys
    k0 = U8TO32_LITTLE(*Key + 0)
    k1 = U8TO32_LITTLE(*Key + 4)
    k2 = U8TO32_LITTLE(*Key + 8)
    k3 = U8TO32_LITTLE(*Key + 12)
   
    ; Generate initial state variables
    *Core\Master\X[0] = k0
    *Core\Master\X[2] = k1
    *Core\Master\X[4] = k2
    *Core\Master\X[6] = k3
    *Core\Master\X[1] = U32V(k3 << 16) | (k2 >> 16)
    *Core\Master\X[3] = U32V(k0 << 16) | (k3 >> 16)
    *Core\Master\X[5] = U32V(k1 << 16) | (k0 >> 16)
    *Core\Master\X[7] = U32V(k2 << 16) | (k1 >> 16)
   
    ; Generate initial counter values
    *Core\Master\C[0] = ROTL32(k2, 16)
    *Core\Master\C[2] = ROTL32(k3, 16)
    *Core\Master\C[4] = ROTL32(k0, 16)
    *Core\Master\C[6] = ROTL32(k1, 16)
   
    *Core\Master\C[1] = (k0 & $FFFF0000) | (k1 & $FFFF)
    *Core\Master\C[3] = (k1 & $FFFF0000) | (k2 & $FFFF)
    *Core\Master\C[5] = (k2 & $FFFF0000) | (k3 & $FFFF)
    *Core\Master\C[7] = (k3 & $FFFF0000) | (k0 & $FFFF)
   
    *Core\Master\Carry = 0
   
    ; Iterate the system four times
   
    For index = 0 To 3
      RABBIT_NextState128(*Core\Master)
    Next
   
    ; Modify the counters
    For Index = 0 To 7
      *Core\Master\C[Index] ! *Core\Master\X[(Index + 4) & 7]
    Next
   
    ; Copy master instance to work instance
   
    For Index = 0 To 7
      *Core\Work\X[Index] = *Core\Master\X[Index]
      *Core\Work\C[Index] = *Core\Master\C[Index]
    Next
   
    *Core\Work\Carry = *Core\Master\Carry
   
  EndProcedure
 
  Procedure RABBIT_InitVectorSetup128(*Core.Core, *InitVector)
   
    ; Temporary variables
    Protected i0.q, i1.q, i2.q, i3.q, Index.l
   
    ; Generate four subvectors
    i0 = U8TO32_LITTLE(*InitVector + 0)
    i2 = U8TO32_LITTLE(*InitVector + 4)
    i1 = (i0 >> 16) | (i2 & $FFFF0000)
    i3 = (i2 << 16) | (i0 & $0000FFFF)
   
    ; Modify counter values
   
    *Core\Work\C[0] = *Core\Master\C[0] ! i0
    *Core\Work\C[1] = *Core\Master\C[1] ! i1
    *Core\Work\C[2] = *Core\Master\C[2] ! i2
    *Core\Work\C[3] = *Core\Master\C[3] ! i3
   
    *Core\Work\C[4] = *Core\Master\C[4] ! i0
    *Core\Work\C[5] = *Core\Master\C[5] ! i1
    *Core\Work\C[6] = *Core\Master\C[6] ! i2
    *Core\Work\C[7] = *Core\Master\C[7] ! i3
   
    ; Copy state variables
   
    For Index = 0 To 7
      *Core\Work\X[Index] = *Core\Master\X[Index]
    Next
   
    *Core\Work\Carry = *Core\Master\Carry
   
    ; Iterate the system four times
   
    For index = 0 To 3
      RABBIT_NextState128(*Core\Work)
    Next
   
  EndProcedure

  Procedure RABBIT_Process_Bytes128(*Core.Core, *Input, *Output, MsgLen.l)
   
    ; Temporary variables
   
    Protected Buffer.Buffer, Index.l
   
    ; Encrypt/decrypt all full blocks
   
    While MsgLen >= 16
     
      ; Iterate the system
      RABBIT_NextState128(*Core\Work)
     
      ; Encrypt/decrypt 16 bytes of data
      PokeU32(*Output + 00, PeekU32(*Input + 00) ! *Core\Work\X[0] ! (*Core\Work\X[5] >> 16) ! U32V(*Core\Work\X[3] << 16))
      PokeU32(*Output + 04, PeekU32(*Input + 04) ! *Core\Work\X[2] ! (*Core\Work\X[7] >> 16) ! U32V(*Core\Work\X[5] << 16))
      PokeU32(*Output + 08, PeekU32(*Input + 08) ! *Core\Work\X[4] ! (*Core\Work\X[1] >> 16) ! U32V(*Core\Work\X[7] << 16))
      PokeU32(*Output + 12, PeekU32(*Input + 12) ! *Core\Work\X[6] ! (*Core\Work\X[3] >> 16) ! U32V(*Core\Work\X[1] << 16))
     
      *Input + 16
      *Output + 16
      MsgLen - 16
     
    Wend
   
    ; Encrypt/decrypt remaining data
   
    If MsgLen <> 0
     
      ; Iterate the system
      RABBIT_NextState128(*Core\Work)
     
      ; Generate 16 bytes of pseudo-random data */
     
      PokeU32(@Buffer + 00, *Core\Work\X[0] ! (*Core\Work\X[5]>>16) ! U32V(*Core\Work\X[3]<<16))
      PokeU32(@Buffer + 04, *Core\Work\X[2] ! (*Core\Work\X[7]>>16) ! U32V(*Core\Work\X[5]<<16))
      PokeU32(@Buffer + 06, *Core\Work\X[4] ! (*Core\Work\X[1]>>16) ! U32V(*Core\Work\X[7]<<16))
      PokeU32(@Buffer + 12, *Core\Work\X[6] ! (*Core\Work\X[3]>>16) ! U32V(*Core\Work\X[1]<<16))
     
      For Index = 0 To MsgLen - 1
        PokeA(*Output, PeekA(*Input) ! Buffer\Buffer[Index])
        *Output + 1
        *Input + 1
      Next
     
    EndIf
   
  EndProcedure

  Procedure RABBIT_Encrypt(*This.Private_Members, *PlainText, *CipheredText, StringByteLength.l)
   
    RABBIT_Process_Bytes128(*This\Core, *PlainText, *CipheredText, StringByteLength)
   
  EndProcedure

  Procedure RABBIT_Decrypt(*This.Private_Members, *PlainText, *CipheredText, StringByteLength.l)
   
    RABBIT_Process_Bytes128(*This\Core, *CipheredText, *PlainText, StringByteLength)
   
  EndProcedure
 
  ; <<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Getters <<<<<

  Procedure.s GetKey(*This.Private_Members)
   
    ProcedureReturn *This\Key
  EndProcedure
 
  Procedure.s GetInitVector(*This.Private_Members)
   
    ProcedureReturn *This\InitVector
  EndProcedure
 
  ; <<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Setters <<<<<

  Procedure SetKey(*This.Private_Members, P_Key.s)
   
    If P_Key <> ""
      *This\Key = P_Key
    Else
      *This\Key = "RabbitCipher"
    EndIf
   
    *This\IsSetupDone = #False
   
  EndProcedure
 
  Procedure SetInitVector(*This.Private_Members, P_InitVector.s)
   
    If P_InitVector <> ""
      *This\InitVector = P_InitVector
    Else
      *This\InitVector = "InitVector"
    EndIf
   
    *This\IsSetupDone = #False
   
  EndProcedure
 
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The RunSetup operator <<<<<
 
  Procedure RunSetup(*This.Private_Members)
   
    NormKey = Normalizer(*This\Key, 128)
    RABBIT_KeySetup128(*This\Core, NormKey)
    FreeMemory(NormKey)
   
    If *This\InitVector <> "NULL"
      NormInitVec = Normalizer(*This\InitVector, 64)
      RABBIT_InitVectorSetup128(*This\Core, NormInitVec)
      FreeMemory(NormInitVec)
    EndIf
   
    *This\IsSetupDone = #True
   
  EndProcedure
 
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Write on file operators <<<<<
 
  Procedure RC_WriteString(*This.Private_Members, FileID.i, P_String.s)
   
    If *This\IsSetupDone = #True
     
      StringMemorySize.q = StringByteLength(P_String) + SizeOf(Character)
      WriteU32(FileID, StringMemorySize)
     
      *CipheredText = AllocateMemory(StringMemorySize)
      RABBIT_Encrypt(*This, @P_String, *CipheredText, StringByteLength(P_String))
      WriteData(FileID, *CipheredText, StringMemorySize)
     
      FreeMemory(*CipheredText)
     
    EndIf
   
  EndProcedure
 
  Procedure RC_WriteByte(*This.Private_Members, FileID.i, P_Value.b)
   
    If P_Value < 0
      Sign.s = "-"
      P_Value = P_Value * -1
    EndIf
   
    RC_WriteString(*This, FileID, Sign + RSet(Str(P_Value), 6, "0"))
   
  EndProcedure
 
  Procedure RC_WriteAsciiCharacter(*This.Private_Members, FileID.i, P_Value.a)
   
    RC_WriteString(*This, FileID, RSet(Str(P_Value), 6, "0"))
   
  EndProcedure
 
  Procedure RC_WriteWord(*This.Private_Members, FileID.i, P_Value.w)
   
    If P_Value < 0
      Sign.s = "-"
      P_Value = P_Value * -1
    EndIf
   
    RC_WriteString(*This, FileID, Sign + RSet(Str(P_Value), 10, "0"))
   
  EndProcedure
 
  Procedure RC_WriteUnicodeCharacter(*This.Private_Members, FileID.i, P_Value.u)
   
    RC_WriteString(*This, FileID, RSet(Str(P_Value), 10, "0"))
   
  EndProcedure
 
  Procedure RC_WriteCharacter(*This.Private_Members, FileID.i, P_Value.c)
   
    RC_WriteString(*This, FileID, RSet(Str(P_Value), 10, "0"))
   
  EndProcedure
 
  Procedure RC_WriteLong(*This.Private_Members, FileID.i, P_Value.l)
   
    If P_Value < 0
      Sign.s = "-"
      P_Value = P_Value * -1
    EndIf
   
    RC_WriteString(*This, FileID, Sign + RSet(Str(P_Value), 22, "0"))
   
  EndProcedure
 
  Procedure RC_WriteQuad(*This.Private_Members, FileID.i, P_Value.q)
   
    If P_Value < 0
      Sign.s = "-"
      P_Value = P_Value * -1
    EndIf
   
    RC_WriteString(*This, FileID, Sign + RSet(Str(P_Value), 42, "0"))
   
  EndProcedure
 
  Procedure RC_WriteInteger(*This.Private_Members, FileID.i, P_Value.i)
   
    If P_Value < 0
      Sign.s = "-"
      P_Value = P_Value * -1
    EndIf
   
    RC_WriteString(*This, FileID, Sign + RSet(Str(P_Value), 42, "0"))
   
  EndProcedure
 
  Procedure RC_WriteFloat(*This.Private_Members, FileID.i, P_Value.f)
   
    RC_WriteString(*This, FileID, StrF(P_Value, 14))
   
  EndProcedure
 
  Procedure RC_WriteDouble(*This.Private_Members, FileID.i, P_Value.d)
   
    RC_WriteString(*This, FileID, StrD(P_Value, 25))
   
  EndProcedure
 
  Procedure RC_WriteData(*This.Private_Members, FileID.i, *Memory, Size.l)
   
    If *This\IsSetupDone = #True
     
      If *Memory <> #Null
       
        *CipheredMemory = AllocateMemory(Size)
        RABBIT_Encrypt(*This, *Memory, *CipheredMemory, Size)
        WriteData(FileID, *CipheredMemory, Size)
        FreeMemory(*CipheredMemory)
       
      EndIf
     
    EndIf
   
  EndProcedure

  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Read on file operators <<<<<
 
  Procedure.s RC_ReadString(*This.Private_Members, FileID.i)
   
    If *This\IsSetupDone = #True
     
      StringMemorySize.q = ReadU32(FileID)
      *PlainText = AllocateMemory(StringMemorySize)
      *CipheredText = AllocateMemory(StringMemorySize)
     
      ReadData(FileID, *CipheredText, StringMemorySize)
     
      RABBIT_Decrypt(*This, *PlainText, *CipheredText, StringMemorySize - SizeOf(Character))
      DecryptedString.s = PeekS(*PlainText)
     
      FreeMemory(*PlainText)
      FreeMemory(*CipheredText)
     
    EndIf
   
    ProcedureReturn DecryptedString
  EndProcedure
 
  Procedure.b RC_ReadByte(*This.Private_Members, FileID.i)
   
    ProcedureReturn Val(RC_ReadString(*This, FileID))
  EndProcedure
 
  Procedure.a RC_ReadAsciiCharacter(*This.Private_Members, FileID.i)
   
    ProcedureReturn Val(RC_ReadString(*This, FileID))
  EndProcedure
 
  Procedure.w RC_ReadWord(*This.Private_Members, FileID.i)
   
    ProcedureReturn Val(RC_ReadString(*This, FileID))
  EndProcedure
 
  Procedure.u RC_ReadUnicodeCharacter(*This.Private_Members, FileID.i)
   
    ProcedureReturn Val(RC_ReadString(*This, FileID))
  EndProcedure
 
  Procedure.c RC_ReadCharacter(*This.Private_Members, FileID.i)
   
    ProcedureReturn Val(RC_ReadString(*This, FileID))
  EndProcedure
 
  Procedure.l RC_ReadLong(*This.Private_Members, FileID.i)
   
    ProcedureReturn Val(RC_ReadString(*This, FileID))
  EndProcedure
 
  Procedure.q RC_ReadQuad(*This.Private_Members, FileID.i)
   
    ProcedureReturn Val(RC_ReadString(*This, FileID))
  EndProcedure
 
  Procedure.i RC_ReadInteger(*This.Private_Members, FileID.i)
   
    ProcedureReturn Val(RC_ReadString(*This, FileID))
  EndProcedure
 
  Procedure.f RC_ReadFloat(*This.Private_Members, FileID.i)
   
    ProcedureReturn ValF(RC_ReadString(*This, FileID))
  EndProcedure
 
  Procedure.d RC_ReadDouble(*This.Private_Members, FileID.i)
   
    ProcedureReturn ValD(RC_ReadString(*This, FileID))
  EndProcedure
 
  Procedure RC_ReadData(*This.Private_Members, FileID.i, *Memory, Size.l)
   
    If *This\IsSetupDone = #True
     
      If *Memory <> #Null
       
        *CipheredMemory = AllocateMemory(Size)
        bytes = ReadData(FileID, *CipheredMemory, Size)
        RABBIT_Decrypt(*This, *Memory, *CipheredMemory, Size)
        FreeMemory(*CipheredMemory)
       
      EndIf
     
    EndIf
   
    ProcedureReturn bytes
  EndProcedure
 
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Destructor <<<<<

  Procedure Free(*This.Private_Members)
   
    FreeStructure(*This)
   
  EndProcedure
 
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Constructor <<<<<

  Procedure.i New(P_Key.s = "RabbitCipher", P_InitVector.s = "InitVector")
   
    *This.Private_Members = AllocateStructure(Private_Members)
    *This\VirtualTable = ?START_METHODS
   
    SetKey(*This, P_Key)
    SetInitVector(*This, P_InitVector)
    RunSetup(*This)
   
    ProcedureReturn *This
  EndProcedure
 
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Virtual Table Entries <<<<<

  DataSection
    START_METHODS:
    Data.i @GetKey()
    Data.i @GetInitVector()
    Data.i @SetKey()
    Data.i @SetInitVector()
    Data.i @RunSetup()
   
    Data.i @RC_WriteString()
    Data.i @RC_WriteByte()
    Data.i @RC_WriteAsciiCharacter()
    Data.i @RC_WriteWord()
    Data.i @RC_WriteUnicodeCharacter()
    Data.i @RC_WriteCharacter()
    Data.i @RC_WriteLong()
    Data.i @RC_WriteQuad()
    Data.i @RC_WriteInteger()
    Data.i @RC_WriteFloat()
    Data.i @RC_WriteDouble()
    Data.i @RC_WriteData()
   
    Data.i @RC_ReadString()
    Data.i @RC_ReadByte()
    Data.i @RC_ReadAsciiCharacter()
    Data.i @RC_ReadWord()
    Data.i @RC_ReadUnicodeCharacter()
    Data.i @RC_ReadCharacter()
    Data.i @RC_ReadLong()
    Data.i @RC_ReadQuad()
    Data.i @RC_ReadInteger()
    Data.i @RC_ReadFloat()
    Data.i @RC_ReadDouble()
    Data.i @RC_ReadData()
   
    Data.i @Free()
    END_METHODS:
  EndDataSection
 
EndModule

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< Code generated in : 00.001 seconds (96000.00 lines/second) <<<<<
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

CompilerIf #PB_Compiler_IsMainFile
 
  UseMD5Fingerprint()
  RC.RabbitCipher::RabbitCipher = RabbitCipher::New()
 
  Varw.w = 32700
  Varl.l = -2147483645
  Varq.q = 9223372036854775800
  Varf.f = 2 * #PI
  Vard.d = 3 * #PI
  Text.s = "J'aime les déesses nordiques super sexy !"
 
  Buffer.i = AllocateMemory(10 * SizeOf(Long))
  FillMemory(Buffer, MemorySize(Buffer), -255, #PB_Long)
 
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test on file"
  Debug ""
  Debug "Original : "
 
  Debug Varw
  Debug Varl
  Debug Varq
  Debug Varf
  Debug Vard
  Debug Text
  Debug ""
 
  If CreateFile(0, "Test.rc")
   
    RC\SetKey("PureBasic 5.72") ; Set the key
    RC\SetInitVector("") ; Restore the default Init vector
    RC\RunSetup()
   
    RC\RC_WriteWord(0, Varw)
    RC\RC_WriteLong(0, Varl) 
    RC\RC_WriteQuad(0, Varq)
   
    RC\SetKey("") ; Restore the default key
    RC\SetInitVector("NULL") ; No Init vector here
    RC\RunSetup()
   
    RC\RC_WriteFloat(0, Varf)
    RC\RC_WriteDouble(0, Vard)
    RC\RC_WriteString(0, Text)
   
    RC\RC_WriteLong(0, MemorySize(Buffer))
    RC\RC_WriteData(0, Buffer, MemorySize(Buffer))
   
    CloseFile(0)
   
  EndIf
 
  Debug "FileSize : " + Str(FileSize("Test.rc"))
  Debug "From the file : "
 
  If ReadFile(1, "Test.rc")
   
    RC\SetKey("PureBasic 5.72") ; Set the key
    RC\SetInitVector("") ; Restore the default Init vector
    RC\RunSetup()
   
    Debug RC\RC_ReadWord(1)
    Debug RC\RC_ReadLong(1)
    Debug RC\RC_ReadQuad(1)
   
    RC\SetKey("") ; Restore the default key
    RC\SetInitVector("NULL")  ; No Init vector here
    RC\RunSetup()
   
    Debug RC\RC_ReadFloat(1)
    Debug RC\RC_ReadDouble(1)
    Debug RC\RC_ReadString(1)
   
    MemorySize.l = RC\RC_Readlong(1)
   
    Buffer2 = AllocateMemory(MemorySize)
    RC\RC_ReadData(1, Buffer2, MemorySize)
   
    Debug "Compare Buffer vs Buffer2 (0 = KO, 1 = OK) -> " + Str(CompareMemory(Buffer, Buffer2, MemorySize))
   
    CloseFile(1)
    DeleteFile("Test.rc")
   
  EndIf
 
  RC\Free()
 
CompilerEndIf

; <<<<<<<<<<<<<<<<<<<<<<<
; <<<<< END OF FILE <<<<<
; <<<<<<<<<<<<<<<<<<<<<<<

_________________
The Stone Age did not end due to a shortage of stones !


Top
 Profile  
Reply with quote  
 Post subject: Re: Rabbit Cipher - Module
PostPosted: Sat Jan 16, 2021 12:57 pm 
Offline
Enthusiast
Enthusiast

Joined: Tue Oct 14, 2014 12:09 pm
Posts: 356
HI STarBootics,
When a false Key is given whn decrypting a file , the programm doesn't do anything , no crash no advertising. Was itpossible to test if the pass encrypt is false and in this case making an advertisment and close the programm.
Thanks in advance


Top
 Profile  
Reply with quote  
 Post subject: Re: Rabbit Cipher - Module
PostPosted: Sun Jan 17, 2021 3:33 am 
Offline
Enthusiast
Enthusiast
User avatar

Joined: Sun Jul 07, 2013 11:35 am
Posts: 587
Location: Canada
loulou2522 wrote:
HI STarBootics,
When a false Key is given whn decrypting a file , the programm doesn't do anything , no crash no advertising. Was itpossible to test if the pass encrypt is false and in this case making an advertisment and close the programm.
Thanks in advance


Yes it's possible, the example I provided was not design with that in mind. The tricks here is to write a specific string in the file when you create it. Then when you read the file you use the password to read the specific string from the file and compare it with the specific string if they are the same then you read the rest of the file if not then you can pop a MessageRequester() telling the user that the password is wrong.

The code snippet should look like this :

Code:
#SpecificString = "SpecificString"

Procedure CreateMySecureFile(FileName.s, Password.s)
 
  If CreateFile(0, FileName)
   
    CustomLib.RabbitCipher::RabbitCipher = RabbitCipher::New(Password, "InitVector")
   
    CustomLib\RC_WriteString(0, #SpecificString)
   
    ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    ; Write the rest of the information you need
   
    CloseFile(0)
   
  EndIf
 
EndProcedure

Procedure ReadMySecureFile(FileName.s, Password.s)
 
  If ReadFile(0, FileName)
   
    CustomLib.RabbitCipher::RabbitCipher = RabbitCipher::New(Password, "InitVector")
   
    If CustomLib\RC_ReadString(0) = #SpecificString
     
      ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
      ; Read the rest of the information you need
     
    Else
     
      MessageRequester("BAD PASSWORD", "The password provided is wrong !")
     
    EndIf
   
    CloseFile(0)
   
  EndIf
 
EndProcedure


I hope the provided snippet will help you to figure out what you want to do.

Best regards
StarBootics

_________________
The Stone Age did not end due to a shortage of stones !


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 47 posts ]  Go to page Previous  1, 2, 3, 4  Next

All times are UTC + 1 hour


Who is online

Users browsing this forum: No registered users and 4 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
Jump to:  

 


Powered by phpBB © 2008 phpBB Group
subSilver+ theme by Canver Software, sponsor Sanal Modifiye