CREATE FUNCTION dbo.fn_IsPrime(@p INT) RETURNS BIT AS BEGIN
DECLARE @i INT = 2, @flag BIT = 1;
WHILE @i * @i <= @p BEGIN
IF @p % @i = 0 BEGIN SET @flag = 0; BREAK; END
SET @i += 1;
END
RETURN @flag;
END
CREATE FUNCTION dbo.fn_IsCoprime(@a INT, @b INT) RETURNS BIT AS BEGIN
DECLARE @tmp INT, @flag BIT = 1;
WHILE @b % @a <> 0 BEGIN
SET @tmp = @a; SET @a = @b % @a; SET @b = @tmp;
END
IF @a = 1 SET @flag = 0; -- GCD=1 互質
RETURN @flag;
END
CREATE PROC dbo.sp_GenRSAKeys @P INT, @Q INT AS BEGIN
IF dbo.fn_IsPrime(@P) = 0 BEGIN PRINT @P + ' 非素數'; RETURN; END
IF dbo.fn_IsPrime(@Q) = 0 BEGIN PRINT @Q + ' 非素數'; RETURN; END
DECLARE @N BIGINT = @P * @Q, @T BIGINT = (@P - 1) * (@Q - 1), @E INT = 2;
PRINT '可用金鑰對 (Public E, Private D):';
WHILE @E < @T BEGIN
IF dbo.fn_IsCoprime(@E, @T) = 0 BEGIN
DECLARE @D INT = 2;
WHILE @D < @N BEGIN
IF (@E * @D) % @T = 1
PRINT CAST(@E AS VARCHAR) + ' ' + CAST(@D AS VARCHAR);
SET @D += 1;
END
END
SET @E += 1;
END
END
CREATE FUNCTION dbo.fn_RSAEncrypt(@Plain NVARCHAR(100), @Key INT, @P INT, @Q INT)
RETURNS NVARCHAR(4000) AS BEGIN
DECLARE @Crypt NVARCHAR(4000) = N'', @N BIGINT = @P * @Q;
DECLARE @Char NVARCHAR(1), @Code BIGINT, @K2 INT, @Val BIGINT, @Hex NVARCHAR(6);
DECLARE @Pos INT = 1, @Len INT = LEN(@Plain);
WHILE @Pos <= @Len BEGIN
SET @Char = SUBSTRING(@Plain, @Pos, 1);
SET @Code = UNICODE(@Char); -- Unicode 碼點
SET @K2 = @Key / 2; SET @Val = 1;
-- 快速模冪:平方乘演算法 (簡化版,實際應用二進位分解)
WHILE @K2 > 0 BEGIN
SET @Val = (CAST(POWER(@Code, 2) AS BIGINT) * @Val) % @N;
SET @K2 -= 1;
END
SET @Val = (@Code * @Val) % @N; -- 最終乘一次
-- 轉 6 位元 16 進位 (不足左補 0)
SET @Hex = RIGHT('000000' + CONVERT(VARCHAR(6), @Val, 2), 6); -- Style 2 = 不含 0x 前綴
SET @Crypt += @Hex;
SET @Pos += 1;
END
RETURN @Crypt;
END
CREATE FUNCTION dbo.fn_RSADecrypt(@Cipher NVARCHAR(4000), @Key INT, @P INT, @Q INT)
RETURNS NVARCHAR(4000) AS BEGIN
DECLARE @Plain NVARCHAR(4000) = N'', @N BIGINT = @P * @Q;
DECLARE @Hex6 NVARCHAR(6), @Val BIGINT, @K2 INT, @CharCode BIGINT;
WHILE LEN(@Cipher) > 0 BEGIN
SET @Hex6 = LEFT(@Cipher, 6);
-- 16 進位字串轉數值
SET @Val = CONVERT(BIGINT, @Hex6, 2); -- Style 2 直接支援
SET @K2 = @Key / 2; SET @CharCode = 1;
WHILE @K2 > 0 BEGIN
SET @CharCode = (CAST(POWER(@Val, 2) AS BIGINT) * @CharCode) % @N;
SET @K2 -= 1;
END
SET @CharCode = (@Val * @CharCode) % @N;
SET @Plain += NCHAR(@CharCode);
SET @Cipher = SUBSTRING(@Cipher, 7, LEN(@Cipher) - 6);
END
RETURN @Plain;
END
-- 選擇素數 P=1163, Q=59 (N=68617 > 65535)
EXEC sp_GenRSAKeys 1163, 59;
-- 輸出金鑰對範例:Public=779, Private=35039
CREATE TABLE #Test (Id INT IDENTITY, Cipher NVARCHAR(4000));
INSERT INTO #Test VALUES (dbo.fn_RSAEncrypt(N'中國人', 779, 1163, 59));
INSERT INTO #Test VALUES (dbo.fn_RSAEncrypt(N'Chinese', 779, 1163, 59));
SELECT *, Plain = dbo.fn_RSADecrypt(Cipher, 35039, 1163, 59) FROM #Test;
/* 結果:
Id Cipher Plain
1 00359B00E6E000EAF5 中國人
2 01075300931B0010A4007EDC004B340074A6004B34 Chinese
*/
| 維度 | 現狀 | 生產級要求 |
|---|---|---|
| 演算法 | 教科書級 RSA (無填充/OAEP) | RSA-OAEP / ECIES |
| 金鑰長度 | ~16 bits (N~68617) | ≥ 2048 bits (N ~ 617 位數) |
| 速度 | 字元級迴圈,極慢 | 硬體加速 / 原生實作 |
| 抗攻擊 | 極易破解 (小數分解) | 抗量子/側信道 |
| 用途 | 教學、極小非敏感標籤 | 金融、個資、機密 |
純 T-SQL 實作 RSA 是理解非對稱加密數學原理的絕佳教具,但**絕不可用於真實保護**。掌握素數判斷、模冪運算、擴展歐幾里得算法 (求模逆) 核心步驟,轉而使用平台內建強加密 API,才是專業開發者的正確姿態。