PL/SQL 中的 RSA 加密





5.00/5 (1投票)
使用 RSA 公钥加密数据
引言
我最近需要使用提供的 RSA 公钥,从 Oracle PL/SQL 包中加密某些信息,以便能够与以这种方式进行身份验证的 Web 服务进行通信。
在互联网上进行了一些研究后,我找不到任何可用的解决方案(免费的)。 找到很多概念、想法和零散的内容,或者付费软件,但要获得一个可用的解决方案,我花费的时间和精力比平时多得多,而且我不得不自己完成大部分工作。
因此,我决定将其发布以供公众了解。
背景
首先,重要的是确保您的环境配置正确
- 您需要确保您的 ORACLE 数据库已安装 JAVA VM。 您可以通过以下方式检查
select comp_name, version, status from dba_registry;
如果它不在那里,则您需要以
SYS
身份登录并执行以下操作SQL> @$ORACLE_HOME/javavm/install/initjvm.sql;
安装 JavaVM 后,一切就绪了。
- 为了本文的目的,我们将使用公钥加密密码,以便它可以被发送并在另一端使用相应的私钥解密。 但我们需要
- 我们的密码(我们将使用“
password
”) - 我们的公钥文件(我将称它为“
rsa.public
”)
- 我们的密码(我们将使用“
在我的例子中,我使用的是 Oracle (11g) 11.2.0.4。
Using the Code
我们需要理解的第一件事是,ORACLE(在 11g 版本中)不提供用于非对称密码学的库。 DBMS_CRYPTO
包只会提供对称密码学。
因此,我们需要创建自己的类来处理它。 我们需要在 Java 中完成它。
创建或替换并编译名为 rsa_crypto
的 Java 源代码,如下所示
import javax.crypto.*;
import java.security.spec.*;
import java.security.*; //PublicKey
public class RSACrypto
{
public static byte[] Encrypt(byte[] cert, byte[] data)
throws Throwable //NoSuchAlgorithmException, InvalidKeySpecException,
//InvalidKeyException, IllegalBlockSizeException,
//NoSuchPaddingException, BadPaddingException
{
byte[] encryptedData = null;
try {
//Generate Public Key with Cert
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(cert);
PublicKey pubKey = keyFactory.generatePublic(pubKeySpec);
//Encrypt
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
encryptedData = cipher.doFinal(data);
return encryptedData;
} catch (Exception e) {
System.out.println( "Unexpected error - " + e.getMessage());
encryptedData = e.getMessage().getBytes();
throw e;
}
}
}
我们的函数将接收 2 个字节数组(证书内容和要加密的数据),并将返回一个包含加密数据的字节数组。
我们将创建我们的包,并在其主体内部声明以下 private
函数
function rsa_encrypt(cert raw, data raw) return raw
AS LANGUAGE JAVA
NAME 'RSACrypto.Encrypt(byte[], byte[]) return byte[]';
然后我们将拥有我们的 login
函数,它将以以下方式使用我们的 JAVA 函数
c_certini constant varchar2(50) := '-----BEGIN PUBLIC KEY-----';
c_certend constant varchar2(50) := '-----END PUBLIC KEY-----';
c_dirname constant varchar2(255) := 'DIRX';
c_key_filename constant varchar2(255) := 'rsa.public';
function login return number is
passpost raw(1024);
res varchar2(1024);
v_fexist boolean;
v_flen number;
v_bsize binary_integer;
v_key utl_file.file_type;
v_cert raw(2048);
v_buffer varchar2(2048);
begin
-- Check and Read Certificate
utl_file.fgetattr(c_dirname, c_key_filename, v_fexist, v_flen, v_bsize);
if not v_fexist then
dbms_output.put_line(c_dirname || '/' || c_key_filename || ' Not Found.');
return -3;
end if;
v_key := utl_file.fopen(c_dirname, c_key_filename,'R');
utl_file.get_raw(v_key,v_cert,v_flen);
utl_file.fclose(v_key);
dbms_output.put_line('Cert Read: ' || utl_raw.cast_to_varchar2(v_cert));
v_buffer := utl_raw.cast_to_varchar2(v_cert);
-- Strip beginning and end.
v_buffer := replace(v_buffer,c_certini,'');
v_buffer := replace(v_buffer,c_certend,'');
v_cert := utl_encode.base64_decode(utl_raw.cast_to_raw(v_buffer));
dbms_output.put_line('Cert Strip: [' || v_buffer || ']');
--Call to JAVA function
begin
passpost:=rsa_encrypt(v_cert,utl_raw.cast_to_raw('Password'));
exception when others then
dbms_output.put_line('Cannot encrypt ' || SQLERRM);
return -4;
end;
if passpost is null then
return -2;
end if;
res:= utl_raw.cast_to_varchar2(utl_encode.base64_encode(passpost));
dbms_output.put_line('Encrypted Signature: ' || res);
return 0;
end;
关注点
基本上我们:打开文件,读取其内容,并将其传递给 Java 函数 Base64Decoded
。
Java 函数将使用接收到的内容创建一个 public
密钥,并使用它加密数据并返回它。
我们将对返回的数据进行 base 64 编码,然后我们可以将其用于我们需要的任何其他用途。
历史
- 2020 年 8 月 12 日:初始版本