在 PL/SQL 中复制 Java 的 Base64 解码

Posted

技术标签:

【中文标题】在 PL/SQL 中复制 Java 的 Base64 解码【英文标题】:Replicate Base64 decoding of Java in PL/SQL 【发布时间】:2017-07-04 06:20:40 【问题描述】:

在 Oracle 中解码 Base64 字符串 (NVARCHAR2) 时,我试图获得与 Java 中相同的结果。

我确实有以下字符串:N'AAECAwQFBgdNu+qx2ZcqsA==',它基本上是打包成 Base64 编码的加密密码。

在 Java 中我正在这样做:

byte[] bytes = Base64.decodeBase64(testValue.getBytes());
for(byte b: bytes)
     System.out.print(String.valueOf(b & 0xFF) + " "); //Decimal (unsigned)    

for(byte b: bytes)
     System.out.print(Integer.toHexString(b & 0xFF) + " "); //Hex 

这会打印我以下内容:

Unsigned: 0 1 2 3 4 5 6 7 77 187 234 177 217 151 42 176 
Hex:      0 1 2 3 4 5 6 7 4d bb  ea  b1  d9  97  2a b0 

现在我想复制 Base64 解码,就像用 Java 制作的一样。我正在尝试关注 PL/SQL 函数:

base64DecodedInput:= UTL_ENCODE.base64_decode(UTL_I18N.STRING_TO_RAW(valueToDecrypt, charset));
DBMS_OUTPUT.PUT_LINE ( 'Base64 decoded is: ' || base64DecodedInput);

字符集是:AL16UTF16 valueToDecrypt 是我上面提到的测试字符串NVARCHAR2(200)

DBMS_OUTPUT 打印我:

Base64 decoded is: 0000004200300105A8308FDD02FE02B11B7901EA02C0

这是错的!...

我错过了什么。 PL/SQL 是否没有使用 url 安全解码之类的?

我被卡住了。

代码是 PL/SQL 函数的一部分:

CREATE OR REPLACE FUNCTION decodeBase64
(valueToDecrypt IN NVARCHAR2)
RETURN NVARCHAR2
AS
   --Declaration area
   charset VARCHAR(100);
   base64DecodedInput RAW(2000); 
   ...

而服务器/数据库设置是:

NLS_RDBMS_VERSION   12.1.0.2.0
NLS_NCHAR_CONV_EXCP FALSE
NLS_LENGTH_SEMANTICS    BYTE
NLS_COMP    BINARY
NLS_DUAL_CURRENCY   $
NLS_TIMESTAMP_TZ_FORMAT DD-MON-RR HH.MI.SSXFF AM TZR
NLS_TIME_TZ_FORMAT  HH.MI.SSXFF AM TZR
NLS_TIMESTAMP_FORMAT    DD-MON-RR HH.MI.SSXFF AM
NLS_TIME_FORMAT HH.MI.SSXFF AM
NLS_SORT    BINARY
NLS_DATE_LANGUAGE   AMERICAN
NLS_DATE_FORMAT DD-MON-RR
NLS_CALENDAR    GREGORIAN
NLS_NUMERIC_CHARACTERS  .,
NLS_NCHAR_CHARACTERSET  AL16UTF16
NLS_CHARACTERSET    WE8MSWIN1252
NLS_ISO_CURRENCY    AMERICA
NLS_CURRENCY    $
NLS_TERRITORY   AMERICA
NLS_LANGUAGE    AMERICAN

【问题讨论】:

【参考方案1】:

看看CAST_TO_RAWDdocumentation:

此函数将使用某些数据字节数表示的 VARCHAR2 值转换为具有该数据字节数的 RAW 值。

你应该使用这个:

base64DecodedInput:= UTL_ENCODE.base64_decode(UTL_RAW.CAST_TO_RAW(TO_CHAR(valueToDecrypt)));
DBMS_OUTPUT.PUT_LINE ( 'Base64 decoded is: ' || base64DecodedInput);

00010203040506074DBBEAB1D9972AB0

哪个(格式化)应该等于期望的结果:

00 01 02 03 04 05 06 07 4D BB EA B1 D9 97 2A B0

NVARCHAR2 用于BASE64 字符串是完全没用的。 BASE64 编码的主要目的是仅用 ASCII 字符表示任意数据,因此 NVARCHAR2 没有任何意义。由于 BASE64 仅包含 ASCII,因此您不必担心CAST(... AS VARCHAR2(200)) 的任何字符编码。

当然,对于decoded 字符串数据类型NVARCHAR2 可能非常有用。

【讨论】:

您完全正确,但是为了保持公司的编码约定,必须以这种方式保存数据。 如何格式化?我仍然得到:Base64 解码为:0000004200300105A8308FDD02FE02B11B7901EA02C0 使用您的代码... test varchar2(200); test:= CAST(valueToDecrypt AS VARCHAR2(200)); 让我遇到同样的错误 看起来CAST(... AS VARCHAR2(200))在PL/SQL中不起作用,试试TO_CHAR(valueToDecrypt)【参考方案2】:

@Wernfried 回答的更好方法是使用转换而不是强制转换。

由于 Java 在此示例中打印 UTF-8 值,因此您必须在解码之前将 NVARCHAR2 也转换为 UTF-8。

base64DecodedInput:= UTL_ENCODE.base64_decode(UTL_I18N.STRING_TO_RAW(valueToDecrypt, conversionCharset));

【讨论】:

以上是关于在 PL/SQL 中复制 Java 的 Base64 解码的主要内容,如果未能解决你的问题,请参考以下文章

在 pl/SQL 中继续声明? [复制]

如何在 SQL 中检索 PL/SQL 记录类型? [复制]

如何在 PL/SQL 中解析逗号分隔的字符串? [复制]

在 Oracle PL/SQL 中复制 SAS DO 循环

在 PL/SQL 中将数据从文本文件复制到 CLOB

PL/SQL中复制粘贴表结构信息