ORACLE数据库中使用JAVA源实现SM3签名算法

目    录

ORACLE数据库中使用JAVA源实现SM3签名算法... 1

1.          JAVA源简介.. 4

2.          JAVA源实现SM3签名... 4

3.          JAVA源使用注意事项... 16

 

 

 

  1. JAVA源简介

      JAVA源使我们可以在ORACLE数据库中实现更多的功能,比如数据库中不便于实现的加密、签名等,但是也应该慎用JAVA源,因为JAVA代码最终执行消耗的是数据库服务器的资源,因此在使用JAVA源时需要考虑对数据库性能的开销,尽量避免使用JAVA源进行Web交互,大量的复杂计算等。

 

  1. JAVA源实现SM3签名

为便于理解,以在数据库中实现SM3签名算法为例演示如何创建并使用JAVA源。

  1. 准备JAVA代码

在JAVA语言的开发IDE中编写好JAVA代码,并测试可以正常运行(尽量将需要调用的方法定义为静态的,便于使用)

ORACLE数据库中使用JAVA源实现SM3签名算法

详细代码如下:

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.util.Arrays;

public class SM3 {

   
private static char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8',
           
'9', 'A', 'B', 'C', 'D', 'E', 'F'};
   
private static final String ivHexStr = "7380166f 4914b2b9 172442d7 da8a0600 a96f30bc 163138aa e38dee4d b0fb0e4e";
   
private static final BigInteger IV = new BigInteger(ivHexStr.replaceAll(" ",
           
""), 16);
   
private static final Integer Tj15 = Integer.valueOf("79cc4519", 16);
   
private static final Integer Tj63 = Integer.valueOf("7a879d8a", 16);
   
private static final byte[] FirstPadding = {(byte) 0x80};
   
private static final byte[] ZeroPadding = {(byte) 0x00};

   
private static int T(int j) {
       
if (j >= 0 && j <= 15) {
           
return Tj15.intValue();
        }
else if (j >= 16 && j <= 63) {
           
return Tj63.intValue();
        }
else {
           
throw new RuntimeException("data invalid");
        }
    }

   
private static Integer FF(Integer x, Integer y, Integer z, int j) {
       
if (j >= 0 && j <= 15) {
           
return Integer.valueOf(x.intValue() ^ y.intValue() ^ z.intValue());
        }
else if (j >= 16 && j <= 63) {
           
return Integer.valueOf((x.intValue() & y.intValue())
                    | (x.intValue() & z.intValue())
                    | (y.intValue() & z.intValue()));
        }
else {
           
throw new RuntimeException("data invalid");
        }
    }

   
private static Integer GG(Integer x, Integer y, Integer z, int j) {
       
if (j >= 0 && j <= 15) {
           
return Integer.valueOf(x.intValue() ^ y.intValue() ^ z.intValue());
        }
else if (j >= 16 && j <= 63) {
            
return Integer.valueOf((x.intValue() & y.intValue())
                    | (~x.intValue() & z.intValue()));
        }
else {
           
throw new RuntimeException("data invalid");
        }
    }

   
private static Integer P0(Integer x) {
       
return Integer.valueOf(x.intValue()
                ^ Integer.rotateLeft(x.intValue(),
9)
                ^ Integer.rotateLeft(x.intValue(),
17));
    }

   
private static Integer P1(Integer x) {
       
return Integer.valueOf(x.intValue()
                ^ Integer.rotateLeft(x.intValue(),
15)
                ^ Integer.rotateLeft(x.intValue(),
23));
    }

   
private static byte[] padding(byte[] source) throws IOException {
       
if (source.length >= 0x2000000000000000l) {
           
throw new RuntimeException("src data invalid.");
        }
       
long l = source.length * 8;
       
long k = 448 - (l + 1) % 512;
       
if (k < 0) {
            k = k +
512;
        }
        ByteArrayOutputStream baos =
new ByteArrayOutputStream();
        baos.write(source);
        baos.write(
FirstPadding);
       
long i = k - 7;
       
while (i > 0) {
            baos.write(
ZeroPadding);
            i -=
8;
        }
        baos.write(long2bytes(l));
       
return baos.toByteArray();
    }

   
private static byte[] long2bytes(long l) {
       
byte[] bytes = new byte[8];
       
for (int i = 0; i < 8; i++) {
            bytes[i] = (
byte) (l >>> ((7 - i) * 8));
        }
       
return bytes;
    }

   
public static byte[] hash(byte[] source) throws IOException {
       
byte[] m1 = padding(source);
       
int n = m1.length / (512 / 8);
       
byte[] b;
       
byte[] vi = IV.toByteArray();
       
byte[] vi1 = null;
       
for (int i = 0; i < n; i++) {
            b = Arrays.copyOfRange(m1, i *
64, (i + 1) * 64);
            vi1 = CF(vi, b);
            vi = vi1;
        }
       
return vi1;
    }

   
private static byte[] CF(byte[] vi, byte[] bi) throws IOException {
       
int a, b, c, d, e, f, g, h;
        a = toInteger(vi,
0);
        b = toInteger(vi,
1);
        c = toInteger(vi,
2);
        d = toInteger(vi,
3);
        e = toInteger(vi,
4);
        f = toInteger(vi,
5);
        g = toInteger(vi,
6);
        h = toInteger(vi,
7);

       
int[] w = new int[68];
       
int[] w1 = new int[64];
       
for (int i = 0; i < 16; i++) {
            w[i] = toInteger(bi, i);
        }
       
for (int j = 16; j < 68; j++) {
            w[j] = P1(w[j -
16] ^ w[j - 9] ^ Integer.rotateLeft(w[j - 3], 15))
                    ^ Integer.rotateLeft(w[j -
13], 7) ^ w[j - 6];
        }
       
for (int j = 0; j < 64; j++) {
            w1[j] = w[j] ^ w[j +
4];
        }
       
int ss1, ss2, tt1, tt2;
       
for (int j = 0; j < 64; j++) {
            ss1 = Integer
                    .rotateLeft(
                            Integer.rotateLeft(a,
12) + e
                                    + Integer.rotateLeft(T(j), j),
7);
            ss2 = ss1 ^ Integer.rotateLeft(a,
12);
            tt1 = FF(a, b, c, j) + d + ss2 + w1[j];
            tt2 = GG(e, f, g, j) + h + ss1 + w[j];
            d = c;
            c = Integer.rotateLeft(b,
9);
            b = a;
            a = tt1;
            h = g;
            g = Integer.rotateLeft(f,
19);
            f = e;
            e = P0(tt2);
        }
       
byte[] v = toByteArray(a, b, c, d, e, f, g, h);
       
for (int i = 0; i < v.length; i++) {
            v[i] = (
byte) (v[i] ^ vi[i]);
        }
       
return v;
    }

   
private static int toInteger(byte[] source, int index) {
        StringBuilder valueStr =
new StringBuilder("");
       
for (int i = 0; i < 4; i++) {
            valueStr.append(
hexDigits[(byte) ((source[index * 4 + i] & 0xF0) >> 4)]);
            valueStr.append(
hexDigits[(byte) (source[index * 4 + i] & 0x0F)]);
        }
       
return Long.valueOf(valueStr.toString(), 16).intValue();

    }

   
private static byte[] toByteArray(int a, int b, int c, int d, int e, int f,
                                     
int g, int h) throws IOException {
        ByteArrayOutputStream baos =
new ByteArrayOutputStream(32);
        baos.write(toByteArray(a));
        baos.write(toByteArray(b));
        baos.write(toByteArray(c));
        baos.write(toByteArray(d));
        baos.write(toByteArray(e));
        baos.write(toByteArray(f));
        baos.write(toByteArray(g));
        baos.write(toByteArray(h));
       
return baos.toByteArray();
    }

   
public static byte[] toByteArray(int i) {
       
byte[] byteArray = new byte[4];
        byteArray[
0] = (byte) (i >>> 24);
        byteArray[
1] = (byte) ((i & 0xFFFFFF) >>> 16);
        byteArray[
2] = (byte) ((i & 0xFFFF) >>> 8);
        byteArray[
3] = (byte) (i & 0xFF);
       
return byteArray;
    }
   
private static String byteToHexString(byte b) {
       
int n = b;
       
if (n < 0)
            n =
256 + n;
       
int d1 = n / 16;
       
int d2 = n % 16;
       
return ""+hexDigits[d1] + hexDigits[d2];
    }

   
public static String byteArrayToHexString(byte[] b) {
        StringBuffer resultSb =
new StringBuffer();
       
for (int i = 0; i < b.length; i++) {

            resultSb.append(byteToHexString(b[i]));
        }
       
return resultSb.toString();
    }

   
public static  String Encode(String str)  {
        String text=
null;
       
try {
            text= SM3.byteArrayToHexString(SM3.hash(str.getBytes()));
        }
catch (IOException e) {
            e.printStackTrace();
        }
       
return  text;
    }


}

 

  1. 使用PLSQL登陆数据库执行JAVA源创建语句

创建JAVA源语法为:create or replace and compile java source named [JAVA源名称] as [JAVA代码]

注意:从导包语句开始均视为JAVA代码,直到java类的结尾

详细执行语句如下:

create or replace and compile java source named sm3 as

import java.io.ByteArrayOutputStream;

import java.io.IOException;

import java.math.BigInteger;

import java.util.Arrays;

 

public class SM3 {

 

    private static char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8',

            '9', 'A', 'B', 'C', 'D', 'E', 'F'};

    private static final String ivHexStr = "7380166f 4914b2b9 172442d7 da8a0600 a96f30bc 163138aa e38dee4d b0fb0e4e";

    private static final BigInteger IV = new BigInteger(ivHexStr.replaceAll(" ",

            ""), 16);

    private static final Integer Tj15 = Integer.valueOf("79cc4519", 16);

    private static final Integer Tj63 = Integer.valueOf("7a879d8a", 16);

    private static final byte[] FirstPadding = {(byte) 0x80};

    private static final byte[] ZeroPadding = {(byte) 0x00};

 

    private static int T(int j) {

        if (j >= 0 & j <= 15) {

            return Tj15.intValue();

        } else if (j >= 16 & j <= 63) {

            return Tj63.intValue();

        } else {

            throw new RuntimeException("data invalid");

        }

    }

 

    private static Integer FF(Integer x, Integer y, Integer z, int j) {

        if (j >= 0 & j <= 15) {

            return Integer.valueOf(x.intValue() ^ y.intValue() ^ z.intValue());

        } else if (j >= 16 & j <= 63) {

            return Integer.valueOf((x.intValue() & y.intValue())

                    | (x.intValue() & z.intValue())

                    | (y.intValue() & z.intValue()));

        } else {

            throw new RuntimeException("data invalid");

        }

    }

 

    private static Integer GG(Integer x, Integer y, Integer z, int j) {

        if (j >= 0 & j <= 15) {

            return Integer.valueOf(x.intValue() ^ y.intValue() ^ z.intValue());

        } else if (j >= 16 & j <= 63) {

            return Integer.valueOf((x.intValue() & y.intValue())

                    | (~x.intValue() & z.intValue()));

        } else {

            throw new RuntimeException("data invalid");

        }

    }

 

    private static Integer P0(Integer x) {

        return Integer.valueOf(x.intValue()

                ^ Integer.rotateLeft(x.intValue(), 9)

                ^ Integer.rotateLeft(x.intValue(), 17));

    }

 

    private static Integer P1(Integer x) {

        return Integer.valueOf(x.intValue()

                ^ Integer.rotateLeft(x.intValue(), 15)

                ^ Integer.rotateLeft(x.intValue(), 23));

    }

 

    private static byte[] padding(byte[] source) throws IOException {

        if (source.length >= 0x2000000000000000l) {

            throw new RuntimeException("src data invalid.");

        }

        long l = source.length * 8;

        long k = 448 - (l + 1) % 512;

        if (k < 0) {

            k = k + 512;

        }

        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        baos.write(source);

        baos.write(FirstPadding);

        long i = k - 7;

        while (i > 0) {

            baos.write(ZeroPadding);

            i -= 8;

        }

        baos.write(long2bytes(l));

        return baos.toByteArray();

    }

 

    private static byte[] long2bytes(long l) {

        byte[] bytes = new byte[8];

        for (int i = 0; i < 8; i++) {

            bytes[i] = (byte) (l >>> ((7 - i) * 8));

        }

        return bytes;

    }

 

    public static byte[] hash(byte[] source) throws IOException {

        byte[] m1 = padding(source);

        int n = m1.length / (512 / 8);

        byte[] b;

        byte[] vi = IV.toByteArray();

        byte[] vi1 = null;

        for (int i = 0; i < n; i++) {

            b = Arrays.copyOfRange(m1, i * 64, (i + 1) * 64);

            vi1 = CF(vi, b);

            vi = vi1;

        }

        return vi1;

    }

 

    private static byte[] CF(byte[] vi, byte[] bi) throws IOException {

        int a, b, c, d, e, f, g, h;

        a = toInteger(vi, 0);

        b = toInteger(vi, 1);

        c = toInteger(vi, 2);

        d = toInteger(vi, 3);

        e = toInteger(vi, 4);

        f = toInteger(vi, 5);

        g = toInteger(vi, 6);

        h = toInteger(vi, 7);

 

        int[] w = new int[68];

        int[] w1 = new int[64];

        for (int i = 0; i < 16; i++) {

            w[i] = toInteger(bi, i);

        }

        for (int j = 16; j < 68; j++) {

            w[j] = P1(w[j - 16] ^ w[j - 9] ^ Integer.rotateLeft(w[j - 3], 15))

                    ^ Integer.rotateLeft(w[j - 13], 7) ^ w[j - 6];

        }

        for (int j = 0; j < 64; j++) {

            w1[j] = w[j] ^ w[j + 4];

        }

        int ss1, ss2, tt1, tt2;

        for (int j = 0; j < 64; j++) {

            ss1 = Integer

                    .rotateLeft(

                            Integer.rotateLeft(a, 12) + e

                                    + Integer.rotateLeft(T(j), j), 7);

            ss2 = ss1 ^ Integer.rotateLeft(a, 12);

            tt1 = FF(a, b, c, j) + d + ss2 + w1[j];

            tt2 = GG(e, f, g, j) + h + ss1 + w[j];

            d = c;

            c = Integer.rotateLeft(b, 9);

            b = a;

            a = tt1;

            h = g;

            g = Integer.rotateLeft(f, 19);

            f = e;

            e = P0(tt2);

        }

        byte[] v = toByteArray(a, b, c, d, e, f, g, h);

        for (int i = 0; i < v.length; i++) {

            v[i] = (byte) (v[i] ^ vi[i]);

        }

        return v;

    }

 

    private static int toInteger(byte[] source, int index) {

        StringBuilder valueStr = new StringBuilder("");

        for (int i = 0; i < 4; i++) {

            valueStr.append(hexDigits[(byte) ((source[index * 4 + i] & 0xF0) >> 4)]);

            valueStr.append(hexDigits[(byte) (source[index * 4 + i] & 0x0F)]);

        }

        return Long.valueOf(valueStr.toString(), 16).intValue();

 

    }

 

    private static byte[] toByteArray(int a, int b, int c, int d, int e, int f,

                                      int g, int h) throws IOException {

        ByteArrayOutputStream baos = new ByteArrayOutputStream(32);

        baos.write(toByteArray(a));

        baos.write(toByteArray(b));

        baos.write(toByteArray(c));

        baos.write(toByteArray(d));

        baos.write(toByteArray(e));

        baos.write(toByteArray(f));

        baos.write(toByteArray(g));

        baos.write(toByteArray(h));

        return baos.toByteArray();

    }

 

    public static byte[] toByteArray(int i) {

        byte[] byteArray = new byte[4];

        byteArray[0] = (byte) (i >>> 24);

        byteArray[1] = (byte) ((i & 0xFFFFFF) >>> 16);

        byteArray[2] = (byte) ((i & 0xFFFF) >>> 8);

        byteArray[3] = (byte) (i & 0xFF);

        return byteArray;

    }

    private static String byteToHexString(byte b) {

        int n = b;

        if (n < 0)

            n = 256 + n;

        int d1 = n / 16;

        int d2 = n % 16;

        return ""+hexDigits[d1] + hexDigits[d2];

    }

 

    public static String byteArrayToHexString(byte[] b) {

        StringBuffer resultSb = new StringBuffer();

        for (int i = 0; i < b.length; i++) {

 

            resultSb.append(byteToHexString(b[i]));

        }

        return resultSb.toString();

    }

 

    public static  String Encode(String str)  {

        String text=null;

        try {

            text= SM3.byteArrayToHexString(SM3.hash(str.getBytes()));

        } catch (IOException e) {

            e.printStackTrace();

        }

        return  text;

    }

 

 

}

 

 

  1. 使用PLSQL登陆数据库执行创建调用JAVA源的函数,便于后续使用

CREATE OR REPLACE FUNCTION SM3_Encrypt (cryptData IN STRING)

   RETURN String

IS

   LANGUAGE JAVA

   NAME 'SM3.Encode(java.lang.String) return String';

 

至此,JAVA源已创建完毕,并且可用用我们创建的自定义函数进行SM3签名。使用效果如下图所示:

ORACLE数据库中使用JAVA源实现SM3签名算法

  1. JAVA源使用注意事项
  • JAVA代码严格区分大小写,因此建议使用支持JAVA语言的IDE,如Eclipes等IDE编写JAVA代码并测试代码执行,不要使用PLSQL或Toad等工具对JAVA源格式化。
  • 不要使用JAVA源进行大量开销服务器资源的功能,如HTTP交互、复杂的计算等,如之前业务交互平台推送使用JAVA源进行HTTP推送消息,可能存在数据库性能问题。
  • JAVA类中尽量使用静态方法来封装需要使用的功能,后续使用方便。