oracle-databasedbms-crypto

dbms_crypto and a Powershell


Can someone help me with code to encrypt a string in Oracle, and decrypt using powershell? AES, DES, either one will do. I feel like I'm close but am missing something...

See also this post: Convert encryption / decryption function in PowerShell to PHP (openssl_)

Using that Powershell encryption I can turn "Its a secret" into "AEe2LSdmwi79UYduDZS7Mg=". The below decrypts that back. But how to do this encrypt in Oracle?

function DecryptDES
    {
    Param(
        [String] $encrypted,
        [byte[]] $Key,
        [byte[]] $Iv
    )
        [byte[]]$NewStr = [System.Convert]::FromBase64String($encrypted)
        $tdsAlg = New-Object System.Security.Cryptography.DESCryptoServiceProvider
        $tdsAlg.Key = $Key
        $tdsAlg.IV = $Iv
        $encrypt = $tdsAlg.CreateDecryptor($tdsAlg.Key, $tdsAlg.IV)
        $msEncrypt = New-Object System.IO.MemoryStream @(,$NewStr)
        $csEncrypt = New-Object System.Security.Cryptography.CryptoStream $msEncrypt, $encrypt, "Read"
        $swEncrypt = New-Object System.IO.StreamReader $csEncrypt
        [String]$result = $swEncrypt.ReadToEnd()
        $swEncrypt.Close()
        $csEncrypt.Close()
        $msEncrypt.Close()
        $encrypt.Clear()
    
        return $result;     
    }
    $enc = [system.Text.Encoding]::UTF8
    $string1 = "PeShVmYq" 
    $data1 = $enc.GetBytes($string1) 
    
    $dec = DecryptDES -encrypted 'AEe2LSdmwi79UYduDZS7Mg==' -Key $data1 -Iv $data1
    Write-Host $dec

So far I have this Oracle SQL:

select           
       dbms_crypto.Encrypt(
       src => UTL_RAW.CAST_TO_RAW('Its a secret'),
       typ => 4353,
       key => UTL_ENCODE.BASE64_DECODE(UTL_RAW.CAST_TO_RAW('PeShVmYq')),
       iv => UTL_ENCODE.BASE64_DECODE(UTL_RAW.CAST_TO_RAW('PeShVmYq')))
from dual

Which outputs:

F480D03A9564CAAD0CD815EA1524B6B7


Solution

  • You need to keep the key and IV as RAW, not base64-encode those; then base64 encode the result of the encrypt call; and finally convert that RAW back to a string:

    select
           utl_raw.cast_to_varchar2(
             utl_encode.base64_encode(
               dbms_crypto.encrypt(
                 src => utl_raw.cast_to_raw('Its a secret'),
                 typ => 4353,
                 key => utl_raw.cast_to_raw('PeShVmYq'),
                 iv => utl_raw.cast_to_raw('PeShVmYq')
               )
             )
           ) as encrypted
    from dual;
    
    ENCRYPTED                                                       
    ----------------------------------------------------------------
    AEe2LSdmwi79UYduDZS7Mg==
    

    As you've specified UTF-8 in your PowerShell script, and just generally really, it would probably be better to do RAW/string conversion with a specific character set too:

    select
           utl_i18n.raw_to_char(
             utl_encode.base64_encode(
               dbms_crypto.encrypt(
                 src => utl_i18n.string_to_raw(data => 'Its a secret', dst_charset => 'AL32UTF8'),
                 typ => 4353,
                 key => utl_i18n.string_to_raw(data => 'PeShVmYq', dst_charset => 'AL32UTF8'),
                 iv => utl_i18n.string_to_raw(data => 'PeShVmYq', dst_charset => 'AL32UTF8')
               )
             ),
             src_charset => 'AL32UTF8'
           ) as encrypted
    from dual;
    

    which gets the same result.


    Just for reference, the typ value 4353 (0x1101) comes from:

    dbms_crypto.encrypt_des + dbms_crypto.chain_cbc + dbms_crypto.pad_pkcs5
    

    The AES256 equivalent would be 4360; but you'd also need a longer key.