Page 2 of 2

Posted: Wed May 03, 2006 4:31 pm
by srod
Excellent. Nicely done. :D

Any problems with zero's in this one? That is, is it possible that one of the encrypted characters could be Chr(0) ?

Posted: Wed May 03, 2006 4:59 pm
by HeX0R
No problem with zero-bytes!

Posted: Wed May 03, 2006 5:17 pm
by srod
Perfect. Thank you for this.

Posted: Wed Aug 09, 2006 6:01 am
by Straker
@HeXOR - Can you help me with this? I took your modified RC4 routine and am trying to convert it to Triple-DES. It seems to be working, but the decrypted string has trailing chars. Maybe this is due to it being a block cipher instead of a stream cipher. I'm stumped.

Code: Select all

;Crypt-Constants
#PROV_RSA_FULL = 1
#ALG_SID_MD5 = 3
#ALG_SID_RC4 = 1
#ALG_SID_RC5 = 13
#ALG_CLASS_DATA_ENCRYPT = 3<<13 ;$6000
#ALG_CLASS_HASH = 4<<13 ;$8000
#ALG_TYPE_ANY = 0
#ALG_TYPE_STREAM = 4<<9
#CALG_MD5 = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_MD5
#ALG_TYPE_BLOCK = 1536
#CRYPT_OAEP = $40
; Valid hashing algorithms:
;
; #ALG_SID_HMAC = 9
; #ALG_SID_MAC = 5
; #ALG_SID_MD2 = 1
; #ALG_SID_SHA = 4
; #ALG_SID_SHA1 = 4
; #ALG_SID_SSL3SHAMD5 = 8
; #CALG_HMAC = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_HMAC
; #CALG_MAC = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_MAC
; #CALG_MD2 = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_MD2
; #CALG_SHA = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_SHA
; #CALG_SHA1 = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_SHA1
; #CALG_SSL3_SHAMD5 = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_SSL3SHAMD5
#CALG_RC4 = #ALG_CLASS_DATA_ENCRYPT|#ALG_TYPE_STREAM|#ALG_SID_RC4
#CALG_RC5 = #ALG_CLASS_DATA_ENCRYPT|#ALG_TYPE_BLOCK|#ALG_SID_RC5
#CRYPT_CREATE_SALT = 4
#CRYPT_EXPORTABLE = 1
#CRYPT_NEWKEYSET = 8
#MS_DEF_PROV = "Microsoft Base Cryptographic Provider v1.0"

; added for Triple DES
#ALG_SID_3DES = 3
#CALG_3DES = #ALG_CLASS_DATA_ENCRYPT|#ALG_TYPE_BLOCK|#ALG_SID_3DES
#MS_ENHANCED_PROV = "Microsoft Enhanced Cryptographic Provider v1.0"

Procedure.s EnCrypt(String$, Key$)
  Protected *Buffer
  *Buffer = AllocateMemory(Len(String$) * 2 + 64)
  DataLength.l = Len(String$)
  PokeS(*Buffer, String$)

  If CryptAcquireContext_(@hProv, #Null, #MS_ENHANCED_PROV, #PROV_RSA_FULL, 0) = 0
    CryptAcquireContext_(@hProv, #Null, #MS_ENHANCED_PROV, #PROV_RSA_FULL, #CRYPT_NEWKEYSET)
  EndIf
  If hProv
    CryptCreateHash_(hProv, #CALG_MD5, 0, 0, @hHash)
    If hHash
      CryptHashData_(hHash, @Key$, Len(Key$), 0)
      ;CryptDeriveKey_(hProv, #CALG_RC4, hHash, #CRYPT_EXPORTABLE, @hKey)
      CryptDeriveKey_(hProv, #CALG_3DES, hHash, #CRYPT_EXPORTABLE, @hKey)
      If hKey
        If CryptEncrypt_(hKey, 0, #True, #Null, *Buffer, @DataLength, Len(String$) * 2 + 64)
        EndIf
        CryptDestroyKey_(hKey)
      EndIf
      CryptDestroyHash_(hHash)
    EndIf
    CryptReleaseContext_(hProv, 0)
  EndIf
  
  result.s = Space(DataLength * 3)
  Base64Encoder(*Buffer, DataLength, @result, DataLength * 3)
  FreeMemory(*Buffer)
  ProcedureReturn result
EndProcedure

Procedure.s Decrypt(String$, Key$)
 
  Protected *Buffer
  *Buffer = AllocateMemory(Len(String$) * 2 + 64)
  DataLength.l = Base64Decoder(@String$, Len(String$), *Buffer, Len(String$) * 2 + 64)
  
  If CryptAcquireContext_(@hProv, #Null, #MS_ENHANCED_PROV, #PROV_RSA_FULL, 0) = 0
    CryptAcquireContext_(@hProv, #Null, #MS_ENHANCED_PROV, #PROV_RSA_FULL, #CRYPT_NEWKEYSET)
  EndIf
  If hProv
    CryptCreateHash_(hProv, #CALG_MD5, 0, 0, @hHash)
    If hHash
      CryptHashData_(hHash, @Key$, Len(Key$), 0)
      CryptDeriveKey_(hProv, #CALG_3DES, hHash, #CRYPT_EXPORTABLE, @hKey)
      If hKey
        If CryptDecrypt_(hKey, 0, #True, 0, *Buffer, @DataLength)
          result.s = PeekS(*Buffer)
        EndIf
        CryptDestroyKey_(hKey)
      EndIf
      CryptDestroyHash_(hHash)
    EndIf
    CryptReleaseContext_(hProv, 0)
  EndIf
  FreeMemory(*Buffer)
  ProcedureReturn result
EndProcedure

lStringToEncrypt.s = "macromedia"
lKey.s = "key"

Debug lStringToEncrypt.s

lEncrypted.s = EnCrypt(lStringToEncrypt.s,lKey.s)

Debug lEncrypted.s

lDeCrypted.s = Decrypt(lEncrypted.s,"key")

Debug lDeCrypted.s
Thanks in advance.

Posted: Fri Aug 18, 2006 11:33 am
by HeX0R
Sorry, i am very stressed at the moment, so i didn't see your post earlier ;)

Just make use of the DataLength-Variable like this:

Code: Select all

;Crypt-Constants
#PROV_RSA_FULL = 1
#ALG_SID_MD5 = 3
#ALG_SID_RC4 = 1
#ALG_SID_RC5 = 13
#ALG_CLASS_DATA_ENCRYPT = 3<<13 ;$6000
#ALG_CLASS_HASH = 4<<13 ;$8000
#ALG_TYPE_ANY = 0
#ALG_TYPE_STREAM = 4<<9
#CALG_MD5 = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_MD5
#ALG_TYPE_BLOCK = 1536
#CRYPT_OAEP = $40
; Valid hashing algorithms:
;
; #ALG_SID_HMAC = 9
; #ALG_SID_MAC = 5
; #ALG_SID_MD2 = 1
; #ALG_SID_SHA = 4
; #ALG_SID_SHA1 = 4
; #ALG_SID_SSL3SHAMD5 = 8
; #CALG_HMAC = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_HMAC
; #CALG_MAC = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_MAC
; #CALG_MD2 = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_MD2
; #CALG_SHA = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_SHA
; #CALG_SHA1 = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_SHA1
; #CALG_SSL3_SHAMD5 = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_SSL3SHAMD5
#CALG_RC4 = #ALG_CLASS_DATA_ENCRYPT|#ALG_TYPE_STREAM|#ALG_SID_RC4
#CALG_RC5 = #ALG_CLASS_DATA_ENCRYPT|#ALG_TYPE_BLOCK|#ALG_SID_RC5
#CRYPT_CREATE_SALT = 4
#CRYPT_EXPORTABLE = 1
#CRYPT_NEWKEYSET = 8
#MS_DEF_PROV = "Microsoft Base Cryptographic Provider v1.0"

; added for Triple DES
#ALG_SID_3DES = 3
#CALG_3DES = #ALG_CLASS_DATA_ENCRYPT|#ALG_TYPE_BLOCK|#ALG_SID_3DES
#MS_ENHANCED_PROV = "Microsoft Enhanced Cryptographic Provider v1.0"

Procedure.s EnCrypt(String$, Key$)
  Protected *Buffer
  *Buffer = AllocateMemory(Len(String$) * 2 + 64)
  DataLength.l = Len(String$)
  PokeS(*Buffer, String$)

  If CryptAcquireContext_(@hProv, #Null, #MS_ENHANCED_PROV, #PROV_RSA_FULL, 0) = 0
    CryptAcquireContext_(@hProv, #Null, #MS_ENHANCED_PROV, #PROV_RSA_FULL, #CRYPT_NEWKEYSET)
  EndIf
  If hProv
    CryptCreateHash_(hProv, #CALG_MD5, 0, 0, @hHash)
    If hHash
      CryptHashData_(hHash, @Key$, Len(Key$), 0)
      ;CryptDeriveKey_(hProv, #CALG_RC4, hHash, #CRYPT_EXPORTABLE, @hKey)
      CryptDeriveKey_(hProv, #CALG_3DES, hHash, #CRYPT_EXPORTABLE, @hKey)
      If hKey
        If CryptEncrypt_(hKey, 0, #True, #Null, *Buffer, @DataLength, Len(String$) * 2 + 64)
        EndIf
        CryptDestroyKey_(hKey)
      EndIf
      CryptDestroyHash_(hHash)
    EndIf
    CryptReleaseContext_(hProv, 0)
  EndIf
 
  result.s = Space(DataLength * 3)
  Base64Encoder(*Buffer, DataLength, @result, DataLength * 3)
  FreeMemory(*Buffer)
  ProcedureReturn result
EndProcedure

Procedure.s Decrypt(String$, Key$)
 
  Protected *Buffer
  *Buffer = AllocateMemory(Len(String$) * 2 + 64)
  DataLength.l = Base64Decoder(@String$, Len(String$), *Buffer, Len(String$) * 2 + 64)
 
  If CryptAcquireContext_(@hProv, #Null, #MS_ENHANCED_PROV, #PROV_RSA_FULL, 0) = 0
    CryptAcquireContext_(@hProv, #Null, #MS_ENHANCED_PROV, #PROV_RSA_FULL, #CRYPT_NEWKEYSET)
  EndIf
  If hProv
    CryptCreateHash_(hProv, #CALG_MD5, 0, 0, @hHash)
    If hHash
      CryptHashData_(hHash, @Key$, Len(Key$), 0)
      CryptDeriveKey_(hProv, #CALG_3DES, hHash, #CRYPT_EXPORTABLE, @hKey)
      If hKey
        If CryptDecrypt_(hKey, 0, #True, 0, *Buffer, @DataLength)
          result.s = PeekS(*Buffer, DataLength)
        EndIf
        CryptDestroyKey_(hKey)
      EndIf
      CryptDestroyHash_(hHash)
    EndIf
    CryptReleaseContext_(hProv, 0)
  EndIf
  FreeMemory(*Buffer)
  ProcedureReturn result
EndProcedure

lStringToEncrypt.s = "macromedia"
lKey.s = "key"

Debug lStringToEncrypt.s

lEncrypted.s = EnCrypt(lStringToEncrypt.s,lKey.s)

Debug lEncrypted.s

lDeCrypted.s = Decrypt(lEncrypted.s,lKey)

Debug lDeCrypted.s

Re: Windows: Encryption with password using the Windows API

Posted: Sat Aug 19, 2006 2:21 pm
by NoahPhense
Nice .. yeah rc4 is good, and modified rc4 is very tight. Especially when
you want it to be machine dependant.

- np

Posted: Mon Aug 21, 2006 8:16 pm
by Straker
Works great HeX0R! Thanks.

And congratulations.

Posted: Mon Feb 12, 2007 6:46 pm
by utopiomania
I'm using Hexor's modified RC4 sample below. The problem is, it fails if compiled to a unicode executable.

Have any of you managed to get them to work in both unicode and non-unicode executables?

Code: Select all

#PROV_RSA_FULL = 1
#CRYPT_NEWKEYSET = 8 
#CRYPT_EXPORTABLE = 1 
#CALG_MD5 = 4 << 13 | 0 | 3 
#CALG_RC4 = 3 << 13 | 4 << 9 | 1
#MS_DEF_PROV = "Microsoft Base Cryptographic Provider v1.0" 

procedure.s enCrypt(string.s, key.s) 
  protected *buffer 
  *buffer = allocateMemory(1024)
  
  dataLength = len(string)
  
  pokeS(*buffer, string) 
  if cryptAcquireContext_(@hProv, #NULL, #MS_DEF_PROV, #PROV_RSA_FULL, 0) = 0 
    cryptAcquireContext_(@hProv, #NULL, #MS_DEF_PROV, #PROV_RSA_FULL, #CRYPT_NEWKEYSET) 
  endIf 
  if hProv 
    cryptCreateHash_(hProv, #CALG_MD5, 0, 0, @hHash) 
    if hHash 
      cryptHashData_(hHash, @key, len(key), 0) 
      cryptDeriveKey_(hProv, #CALG_RC4, hHash, #CRYPT_EXPORTABLE, @hKey) 
      if hKey 
        if cryptEncrypt_(hKey, 0, #TRUE, #NULL, *buffer, @dataLength, 1024) 
        endIf 
        cryptDestroyKey_(hKey) 
      endIf 
      cryptDestroyHash_(hHash) 
    endIf 
    cryptReleaseContext_(hProv, 0) 
  endIf 

  result.s = "" 
  for i = 0 to dataLength - 1 
    result + rset(hex(peekB(*buffer + i) & $FF), 2, "0") 
  next i 
  freeMemory(*buffer) 
  procedureReturn result 
endProcedure 

procedure.s decrypt(string.s, key.s) 
  protected *buffer 
  *buffer = allocateMemory(1024) 
  result.s = "" 
  o = 0 
  for i = 1 to len(string) step 2 
    hi = asc(mid(string, i, 1)) - 48 
    if hi > 9 
      hi - 7 
    endIf 
    lo = asc(mid(string, i + 1, 1)) - 48 
    if lo > 9 
      lo - 7 
    endIf 
    pokeB(*buffer + o, (hi * 16) + lo) 
    o + 1 
  next i
    
  datalength = len(string) / 2
  
  if cryptAcquireContext_(@hProv, #NULL, #MS_DEF_PROV, #PROV_RSA_FULL, 0) = 0 
    cryptAcquireContext_(@hProv, #NULL, #MS_DEF_PROV, #PROV_RSA_FULL, #CRYPT_NEWKEYSET) 
  endIf 
  if hProv 
    cryptCreateHash_(hProv, #CALG_MD5, 0, 0, @hHash) 
    if hHash 
      cryptHashData_(hHash, @key, len(key), 0) 
      cryptDeriveKey_(hProv, #CALG_RC4, hHash, #CRYPT_EXPORTABLE, @hKey) 
      if hKey 
        if cryptDecrypt_(hKey, 0, #TRUE, 0, *buffer, @dataLength) 
          result = peekS(*buffer) 
        endIf 
        cryptDestroyKey_(hKey) 
      endIf 
      cryptDestroyHash_(hHash) 
    endIf 
    cryptReleaseContext_(hProv, 0) 
  endIf 
  freeMemory(*buffer) 
  procedureReturn result 
endProcedure

e.s = "14c4b06b824ec593239362517f538b29"
d.s = encrypt(e, "abcd")
messageRequester("Result", "Encode: " + e + #CRLF$ + "Decode: " + decrypt(d, "abcd")) 

end

Posted: Mon Feb 12, 2007 9:37 pm
by ABBKlaus
only a suggestion :oops: , but base64Encoder/Decoder is not unicode compatible.
Memory Viewer shows this in unicode
008947D0 74 4B 7A 63 73 58 34 54 4D 32 79 4E 6D 58 70 32 tKzcsX4TM2yNmXp2
008947E0 44 4A 63 44 31 4F 33 30 7A 4E 45 34 47 2B 32 45 DJcD1O30zNE4G+2E
008947F0 69 50 76 31 51 2F 48 42 46 71 67 3D 00 00 20 00 iPv1Q/HBFqg=.. .
00894800 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 . . . . . . . .

Posted: Mon Feb 12, 2007 10:28 pm
by utopiomania
Seems from the helpfile that you're right. I've posted another above without the base64 stuff.
If compiled to unicode, it decrypts only half the string:

Code: Select all

Encode: 14c4b06b824ec593239362517f538b29
Decode: 14c4b06b824ec593
So, we're half-way there :) but I can't figure out where things go wrong.

Posted: Mon Feb 12, 2007 11:59 pm
by utopiomania
Maybe this is it. I went back to El-Chonis original post, and used a memory buffer instead of a string
to avoid problems with zeroes in the cipher string.

Code: Select all

#PROV_RSA_FULL = 1
#CRYPT_NEWKEYSET = 8 
#CRYPT_EXPORTABLE = 1 
#CALG_MD5 = 4 << 13 | 0 | 3 
#CALG_RC4 = 3 << 13 | 4 << 9 | 1
#MS_DEF_PROV = "Microsoft Base Cryptographic Provider v1.0" 

procedure encrypt(*mem, length, password$) 
  if cryptAcquireContext_(@hProv, #NULL, #NULL, #PROV_RSA_FULL, 0) = 0 
    cryptAcquireContext_(@hProv, #NULL, #NULL, #PROV_RSA_FULL, #CRYPT_NEWKEYSET) 
  endIf 
  cryptCreateHash_(hProv, #CALG_MD5, 0, 0, @hHash) 
  cryptHashData_(hHash, password$, Len(password$), 0) 
  cryptDeriveKey_(hProv, #CALG_RC4, hHash, #CRYPT_EXPORTABLE, @hKey) 
  cryptEncrypt_(hKey, 0, #TRUE, #NULL, *mem, @length, length) 
  cryptDestroyKey_(hKey) 
  cryptDestroyHash_(hHash) 
  cryptReleaseContext_(hProv, 0) 
endProcedure 

procedure decrypt(*mem, length, password$) 
  if cryptAcquireContext_(@hProv, #NULL, #NULL, #PROV_RSA_FULL, 0) = 0 
    cryptAcquireContext_(@hProv, #NULL, #NULL, #PROV_RSA_FULL, #CRYPT_NEWKEYSET) 
  endIf 
  cryptCreateHash_(hProv, #CALG_MD5, 0, 0, @hHash) 
  cryptHashData_(hHash, password$, len(password$), 0) 
  cryptDeriveKey_(hProv, #CALG_RC4, hHash, #CRYPT_EXPORTABLE, @hKey) 
  cryptDecrypt_(hKey, 0, #TRUE, 0, *mem, @length) 
  cryptDestroyKey_(hKey) 
  cryptDestroyHash_(hHash) 
  cryptReleaseContext_(hProv, 0) 
endProcedure 

e.s = "1089338MSHMFSFSYUS3783264P973AS3M3R8YSN4RTR67NSZ187TS3T170SEMS3298YMYMAY31"
lim = len(e) * 2
*mem = allocateMemory(lim)
*ptr = *mem
copyMemoryString(@e, @*ptr)

debug peekS(*mem)
encrypt(*mem, lim, "abcd")
debug peekS(*mem)
debug str(peekC(*mem + 57)) + " at offset 57"
decrypt(*mem, lim, "abcd")
debug peekS(*mem)

end

Posted: Sat Feb 16, 2008 7:34 am
by Elias Montoya
I see this thread is not very old, so i might as well try.
im trying to port this pyton code to pb:

Code: Select all

def mbi_encrypt(key, nonce):
    def derive_key(key, magic):
        hash1 = HMAC.new(key, magic, SHA).digest()
        
        hash2 = HMAC.new(key, hash1 + magic, SHA).digest()
        hash3 = HMAC.new(key, hash1, SHA).digest()
        
        hash4 = HMAC.new(key, hash3 + magic, SHA).digest()
        
        return hash2 + hash4[0:4]

    #
    # Read key and generate two derived keys
    #
    
    key1 = standard_b64decode(key)
    key2 = derive_key(key1, "WS-SecureConversationSESSION KEY HASH")
    key3 = derive_key(key1, "WS-SecureConversationSESSION KEY ENCRYPTION")
    
    #
    # Create a HMAC-SHA-1 hash of nonce using key2
    #
    
    hash = HMAC.new(key2, nonce, SHA).digest()
    
    #
    # Encrypt nonce with DES3 using key3
    #
    
    # IV: 8 bytes of random data
    iv = randpool.KeyboardRandomPool().get_bytes(8)
    obj = DES3.new(key3, DES3.MODE_CBC, iv)
    
    # XXX: win32's Crypt API seems to pad the input with 0x08 bytes to align on 72/36/18/9 boundary
    ciph = obj.encrypt(nonce + "\x08\x08\x08\x08\x08\x08\x08\x08")

    #
    # Generate the blob
    #

    blob = struct.pack("<LLLLLLL", 28, CRYPT_MODE_CBC, CALC_3DES, CALG_SHA1,
                       len(iv), len(hash), len(ciph))
    blob += iv + hash + ciph
    
    return standard_b64encode(blob)
Complete reference in this link:
http://www.openrce.org/blog/view/449/MS ... scheme_REd

The part that is giving me problems is the "# Encrypt nonce with DES3 using key3 ". i think the DES3 code that hexor posted can be used. But where do i use the IV part??

Would you guys help me? :)

Posted: Wed Sep 24, 2008 1:31 pm
by PB
Just wanted to mention that this RC4 code using the Windows API is not
reliable between PCs. What it encodes on my home PC doesn't decode
on my work PC, making it useless for portability. Bear that in mind.