javarc4演算法
曾經實驗室的帶動,加上最近在上網路安全與管理的專業選修課,對加密演算法有了濃厚的興趣。老師留了一次作業,用自己的學號為密鑰,加密一句話,使用RC4加密演算法。
圖書館查找資料,發現RC4演算法還是比較容易理解的。於是動手實現出來。不多說廢話,還是貼代碼吧。我寫的注釋還算清楚。
先貼一個含main函數的核心演算法類,有測試,可以看看最後輸出了什麼^.^
import java.io.UnsupportedEncodingException;
public class Arithmetic {
public static void swap(int x,int y){
int temp;
temp=x;
x=y;
y=temp;
}
public static void main(String[] args) throws UnsupportedEncodingException {
// 密鑰(我的學號)
byte K[]={0,6,1,6,1,0,0,4};
int S[]=new int[256];//狀態矢量S
int T[]=new int[256];//臨時矢量T
// 初始化狀態矢量S,同時生成臨時矢量T
for(int i=0;i<256;i++){
S[i]= i;
T[i]=K[i%K.length];
}
//用T使S置換
{
int j=0;
for(int i=0;i<256;i++){
j=(j+(int)S[i]+(int)T[i])%256;
swap(S[i],S[j]);
}
}
int i = 0,j=0;
boolean tt=true;
int c=0;
int t;
byte k;//密鑰流的當前位元組
byte C[]="套范續".getBytes();
System.out.println(C[3]);
byte P[]=new byte[C.length];
while(c<6){
i=(i+1)%256;
j=(j+S[i])%256;
swap(S[i],S[j]);
t=((S[i]+S[j])%256);
k=(byte) S[t];
// C[c]=(byte) (k^P[c]);
// System.out.print(C[c]+" ");
P[c]=(byte) (k^C[c]);
System.out.print(P[c]+" ");
c++;
}
System.out.println(new String(P,"GBK"));
// byte rr[]={65};
// System.out.println(new String(rr));
}
}
再來貼一下以界面展示的代碼,比較長。用的就是普通的jsp+servlet。
核心類:
public class RC4 {
// 密鑰(我的學號)
byte K[]={0,6,1,6,1,0,0,4};
void swap(int x,int y){
int temp;
temp=x;
x=y;
y=temp;
}
public String encrypt(String plaintext){
String ciphertext=new String();
int S[]=new int[256];//狀態矢量S
int T[]=new int[256];//臨時矢量T
// 初始化狀態矢量S,同時生成臨時矢量T
for(int i=0;i<256;i++){
S[i]= i;
T[i]=K[i%K.length];
}
//用T使S置換
{
int j=0;
for(int i=0;i<256;i++){
j=(j+(int)S[i]+(int)T[i])%256;
swap(S[i],S[j]);
}
}
int i = 0,j=0;
int c=0;
int t;
byte k;//密鑰流的當前位元組
byte P[]=plaintext.getBytes();
byte C[]=new byte[P.length];
while(c<P.length){
i=(i+1)%256;
j=(j+S[i])%256;
swap(S[i],S[j]);
t=((S[i]+S[j])%256);
k=(byte) S[t];
C[c]=(byte) (k^P[c]);
System.out.print(C[c]+" ");
c++;
}
System.out.println(new String(C));
ciphertext=new String(C);
return ciphertext;
}
}
頁面:
home.jsp
<%@ page language="java" import="java.util.*,core.ChangeCharset" pageEncoding="GBK"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>My JSP 'home.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<link rel="stylesheet" type="text/css" href="styles.css">
<script type="text/javascript">
function doencrypt(){
document.form1.domethod.value="encrypt";
document.form1.submit();
}
function dodecipher(){
document.form1.domethod.value="decipher";
document.form1.submit();
}
</script>
</head>
<body>
<%@ include file="header.jsp" %>
<div id="show" >
<form name="form1" method="post" action="Manage">
<input type="hidden" name="domethod" />
請輸入一句話:<input type="text" name="plainText" />
<a href="javascript:void(0)" onclick="javascript:doencrypt();return false;">加密</a>
</br>
</br>
<%String cipher=(String)request.getAttribute("cipher");
if(cipher==null){
cipher="";
}
String plain1=(String)request.getAttribute("plain1");
if(plain1==null){
plain1="";
}
%>
所得密文:<input type="text" name="cipherText" value="<%=cipher %>" />
<a href="javascript:void(0)" onclick="javascript:dodecipher();return false;">解密</a>
</br>
</br>
所得明文:<input type="text" name="getPlain" value="<%=plain1 %>" />
</form>
</div>
<%@ include file="footer.jsp" %>
</body>
</html>
header.jsp(這個沒什麼意思,但還是給出來吧,給初學html的朋友一些借鑒)
<%@ page language="java" import="java.util.*" pageEncoding="gb2312"%>
<div id="header" align="center">
<h1>RC4加密演算法測試系統</h1>
<hr>
</div>
footer.jsp
<%@ page language="java" import="java.util.*" pageEncoding="gb2312"%>
<div align="center">
<hr>
<table>
<tr><td>Powered by Tasu</td></tr>
<tr><td>Copyright@Tasusparty Studio 2009-2010 All rights reserved</td></tr>
</table>
</div>
styles.css(給出來省事一些,諸位看起來方便)
body{
margin:0px;
padding:0px;
background: #E6EAE9;
font-family: "Lucida Sans Unicode", "宋體", "新宋體", Arial, Verdana, serif;
color:#4f6b72;
font-size:12px;
line-height:150%;
}
#show{
margin:0px auto;
padding:0px;
width:200px;
height:400px
}
#header{
margin:30px auto;
}
處理的Servlet:
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import core.ChangeCharset;
import core.RC4;
public class Manage extends HttpServlet {
public Manage() {
super();
}
public void destroy() {
super.destroy(); // Just puts "destroy" string in log
// Put your code here
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request,response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("GBK"); //設置輸入編碼格式
response.setContentType("text/html;charset=GBK"); //設置輸出編碼格式
String domethod=request.getParameter("domethod");
if(domethod.equals("encrypt")){
String plain=request.getParameter("plainText");
RC4 rc4=new RC4();
String cipher=rc4.encrypt(plain);
System.out.println(cipher);
request.setAttribute("cipher", cipher);
request.getRequestDispatcher("home.jsp").forward(request, response);
}
if(domethod.equals("decipher")){
String cipher=request.getParameter("cipherText");
RC4 rc4=new RC4();
String plain=rc4.encrypt(cipher);
request.setAttribute("plain1", plain);
request.getRequestDispatcher("home.jsp").forward(request, response);
}
}
public void init() throws ServletException {
// Put your code here
}
}(中網互贏 手機客戶端)
② java如何讀取一個加密後的.xls文件
近日來,研究了一下Excel Biff8(xls 97-2007)與OpenXML(ECMA-376)的加密文檔的讀取(這還是為了我們世界先進Grid而做的 ^__^)。有些成果,寫在這里,希望能給要做類似功能的XD們一些參考。
如有不詳,請聯系:[email protected] / [email protected]
前提:
1. 加密文檔:指Wookbook級的加密,就是在Save Excel文檔時在General Settings中設置open password之後的文檔;
2. 打開:需要用戶傳入密碼。並非破解。但請勿將本文方法添加暴力模塊使用 :-) ;
3. 本文涉及較多為,密鑰計算,關於解密細節請參考微軟相關文檔;
使用的加密演算法: RC4, SHA1, MD5, AES-128(其中RC4並不包含在所有版本的.NET Framework中,AES演算法可以在.NET Framework 3.5中找到)
本文示例依賴 .NET Framework 3.5
A. Biff8 的加密文檔讀取
1. 通過文檔中FILEPASS的record取得,文檔的加密信息(關於Biff文檔的格式問題,請參閱Biff的微軟文檔)
其中Biff8可以使用兩種方法加密:Biff8標准加密演算法和Biff8擴充加密演算法。本文主要討論最常用的Biff標准加密演算法
2. 通過FILEPASS的結構,獲得如下信息:
salt(加密隨機數,16 bytes)
password verifier (密碼效驗器,16 bytes)
password verifier hash(密碼效驗器Hash,16 bytes)
3. 通過以上信息,生成解密key。並通過密碼效驗器,驗證密碼:
i. 將密碼轉化成unicode數組,並進行MD5 Hash;
ii. 將hash結果與salt串聯,然後將byte數組,反復串聯16次(336 bytes) ,然後再進行MD5 Hash;
iii. 將上步hash結果的前五位,串聯上4 bytes的block值(在密碼驗證階段為0,在以後解密階段為block的index) ,然後進行MD5 Hash;
iv. 將上步hash結果的前16位,作為key
v. 使用RC4對稱加密演算法,將password verifier和password verifier hash分別解密,然後對password verifier的解密結果進行MD5 hash,其值應和password verifier hash的解密結果一致,即為密碼正確。
vi. 之後進行逐個record的解密。excel biff8加密原則基本為,record的標示不加密,長度不加密,個別record不加密(見文檔);另外,在record解密時,還需要通過block的值重新計算解密key,block的大小為1024.
4. 詳細請參照示例代碼;
B. OpenXML(ECMA-376) 加密文檔的讀取
1. 通常來說,xlsx文件相當於一個zip文件,可以用zip程序,直接打開。而在加密後,為了安全性考慮,微軟使用了 structured storage(一種OLE文檔存儲方式)存儲(可以用7-zip或者OLE document viewer打開,windows也有相應API來操作此類結構)。在上述文檔中,有一個叫做「EncryptedPackage」加密的package,就是一個zip包通過AES演算法進行加密之後的結果。我們將使用和A一樣的方式來檢查密碼,但生成key的方法不同;OpenXML的加密類型也有多種,我們這里就討論常用的用AES-128進行加密的流程;
2. 通過文檔的「EncryptedInfo」部分,需要過的一下信息(關於此部分的結構,請參考[MS-OFFCRYPTO].pdf)
salt(加密隨機數,16 bytes)
password verifier (密碼效驗器,16 bytes)
password verifier hash(密碼效驗器Hash,32 bytes)
3. 通過以上信息,生成解密key。並通過密碼效驗器,驗證密碼:
i. 首先,定義一個H函數,其有兩個輸入,內部使用SHA1演算法將兩個輸入串聯之後的結果hash返回;
ii. 先將salt與password(password的unicode數組)進行H計算,h = H(salt, password) ;
iii.然後設iterator為0x00000000,將其轉為4byte的數組,然後進行H計算,h1 = H(iterator, h);
iv.將上面的iterator遞增一,然後再與h1進行H計算,h2 = H(iterator,h1),然後將這個遞增和計算過程重復50000次,最後計算過的iterator為49999即可;
v. 現在有計算結果h50000,將h50000再與0x00000000(4 byte數組)進行H計算,Hfinal = H(h50000, 0x00000000);
vi. 生成一個64byte的數組,將每位都初始化成0x36,然後將這個數組與Hfinal異或;(關於這個地方,微軟文檔中寫的有錯誤,按照原文的方法生成的key不正確,要不是文檔的作者回信告訴我要使用這個法子,就算我想破頭也想不出來啊 T__T)
vii.將異或結果,進行SHA1 hash,結果的前16byte就是解密的key;
viii.初始化AES演算法,key長度為128,模式為ECB模式,Padding為none; 然後將password verifier 和password verifier hash分別解密;
ix. password verifier 解密後的SHA1 hash結果應該與password verifier hash解密後的前20byte相同;
4. 關於"EncryptedPackage" 的解密則更為簡單,只許將「EncryptedPackage」讀入,去除前8byte的size信息後,進行AES解密,即為未加密的標准openxml文檔。
參考:
[MS-OFFCRYPTO].pdf
[MS-XLS].pdf
ECMA-376 standards
Reply by "winnow", 2008-09-10, 1:17
-----------------------------------------------------
總結一下, 關於這兩種基於密碼的加密方法, 基本上都是基於RFC2898 建議, 思想是這樣:
輸入是用戶的密碼:password, 輸出是提供給加密函數的密鑰:key.
考慮安全, 需要使同樣的password生成的key不一樣, 這樣用相同的password加密後的結果就無法比較. 需要一個隨機數salt.
另外, 為了使暴力破解的代價增大, 考慮使用一個循環多次的過程, 需要循環次數:iteration_count.
概念上, 生成方法為: 將password和salt進行某種運算, 配合一個Hash函數, 以某種方式循環iteration_count次, 在最後的結果里取一部分作為key輸出.
具體參照RFC2898中的建議方法PBKDF1和PBKDF2.
這樣, 用戶輸入的密碼與一個隨機數組合, 經過一定代價的運算, 就生成了可以供加密函數使用的密鑰. 使用這個密鑰和一個加密函數, 就可以進行加密了.
在應用中, 為了快速判斷密碼是否錯誤. 生成一個隨機數verifier, 用一個Hash函數計算verifier的hash值:verifier_hash, 分別加密verifier和verifier_hash並保存.
解密的時候, 先分別解密出verifier和verifier_hash, 計算verifier的hash值, 與verifier_hash比較, 如果一致, 即說明密碼正確.
③ 求RC4演算法的原理,最好用通俗的語言講解,能打下比方更好了(本人能看懂一點VB跟C)
RC4經典加密演算法VB版本代碼
VB版rc4演算法
Public Sub main()
Dim key As String
For i = 1 To 16
Randomize
key = key & Chr(Rnd * 255)
Next i
MsgBox RC4(RC4("Welcome To Plindge Studio!", key), key)
End Sub
Public Function RC4(inp As String, key As String) As String
Dim S(0 To 255) As Byte, K(0 To 255) As Byte, i As Long
Dim j As Long, temp As Byte, Y As Byte, t As Long, x As Long
Dim Outp As String
For i = 0 To 255
S(i) = i
Next
j = 1
For i = 0 To 255
If j > Len(key) Then j = 1
K(i) = Asc(Mid(key, j, 1))
j = j + 1
Next i
j = 0
For i = 0 To 255
j = (j + S(i) + K(i)) Mod 256
temp = S(i)
S(i) = S(j)
S(j) = temp
Next i
i = 0
j = 0
For x = 1 To Len(inp)
i = (i + 1) Mod 256
j = (j + S(i)) Mod 256
temp = S(i)
S(i) = S(j)
S(j) = temp
t = (S(i) + (S(j) Mod 256)) Mod 256
Y = S(t)
Outp = Outp & Chr(Asc(Mid(inp, x, 1)) Xor Y)
Next
RC4 = Outp
End Function
④ RC4的漏洞
由於RC4演算法加密是採用的xor,所以,一旦子密鑰序列出現了重復,密文就有可能被破解。關於如何破解xor加密,請參看Bruce Schneier的Applied Cryptography一書的1.4節Simple XOR,在此我就不細說了。那麼,RC4演算法生成的子密鑰序列是否會出現重復呢?由於存在部分弱密鑰,使得子密鑰序列在不到100萬位元組內就發生了完全的重復,如果是部分重復,則可能在不到10萬位元組內就能發生重復,因此,推薦在使用RC4演算法時,必須對加密密鑰進行測試,判斷其是否為弱密鑰。其不足主要體現於,在無線網路中IV(初始化向量)不變性漏洞。
而且,根據目前的分析結果,沒有任何的分析對於密鑰長度達到128位的RC4有效,所以,RC4是目前最安全的加密演算法之一,大家可以放心使用!
分布式代碼管理網站Github從2015年1月5日將停止對RC4的支持,RC4作為一種老舊的驗證和加密演算法易於受到黑客攻擊。這意味著,用戶在使用Windows XP系統上的IE瀏覽器時將無法進入github.com網站
⑤ 想用RC4演算法加密一下Byte數組,求助一下大牛,有沒有相關的思路
.net和java環境都直接支持RC4演算法。直接應用就可以。
⑥ 求大神幫我注釋下代碼,主要是兩行*號中間的,謝謝了。java,關於RC4加解密演算法。
{
int[] iS = new int[256]; //定義iS int型數組
byte[] iK = new byte[256]; //定義iK byte型數組
for (int i=0;i<256;i++) //循環256次 給iS初始化值
iS[i]=i;
int j = 1;
for (short i= 0;i<256;i++) //循環256次
{
iK[i]=(byte)aKey.charAt((i % aKey.length())); //從aKey里取值賦予iK
}
⑦ RC4的原理
RC4演算法的原理很簡單,包括初始化演算法(KSA)和偽隨機子密碼生成演算法(PRGA)兩大部分。假設S-box的長度為256,密鑰長度為Len。先來看看演算法的初始化部分(用C代碼表示):
其中,參數1是一個256長度的char型數組,定義為: unsigned char sBox[256];
參數2是密鑰,其內容可以隨便定義:char key[256];
參數3是密鑰的長度,Len = strlen(key); /*初始化函數*/voidrc4_init(unsignedchar*s,unsignedchar*key,unsignedlongLen){inti=0,j=0;chark[256]={0};unsignedchartmp=0;for(i=0;i<256;i++){s[i]=i;k[i]=key[i%Len];}for(i=0;i<256;i++){j=(j+s[i]+k[i])%256;tmp=s[i];s[i]=s[j];//交換s[i]和s[j]s[j]=tmp;}}在初始化的過程中,密鑰的主要功能是將S-box攪亂,i確保S-box的每個元素都得到處理,j保證S-box的攪亂是隨機的。而不同的S-box在經過偽隨機子密碼生成演算法的處理後可以得到不同的子密鑰序列,將S-box和明文進行xor運算,得到密文,解密過程也完全相同。
再來看看演算法的加密部分(用C代碼表示):
其中,參數1是上邊rc4_init函數中,被攪亂的S-box;
參數2是需要加密的數據data;
參數3是data的長度. /*加解密*/voidrc4_crypt(unsignedchar*s,unsignedchar*Data,unsignedlongLen){inti=0,j=0,t=0;unsignedlongk=0;unsignedchartmp;for(k=0;k<Len;k++){i=(i+1)%256;j=(j+s[i])%256;tmp=s[i];s[i]=s[j];//交換s[x]和s[y]s[j]=tmp;t=(s[i]+s[j])%256;Data[k]^=s[t];}}最後,在main函數中,調用順序如下: intmain(){unsignedchars[256]={0},s2[256]={0};//S-boxcharkey[256]={justfortest};charpData[512]=這是一個用來加密的數據Data;unsignedlonglen=strlen(pData);inti;printf(pData=%s
,pData);printf(key=%s,length=%d
,key,strlen(key));rc4_init(s,(unsignedchar*)key,strlen(key));//已經完成了初始化printf(完成對S[i]的初始化,如下:
);for(i=0;i<256;i++){printf(%02X,s[i]);if(i&&(i+1)%16==0)putchar('
');}printf(
);for(i=0;i<256;i++)//用s2[i]暫時保留經過初始化的s[i],很重要的!!!{s2[i]=s[i];}printf(已經初始化,現在加密:
);rc4_crypt(s,(unsignedchar*)pData,len);//加密printf(pData=%s
,pData);printf(已經加密,現在解密:
);//rc4_init(s,(unsignedchar*)key,strlen(key));//初始化密鑰rc4_crypt(s2,(unsignedchar*)pData,len);//解密printf(pData=%s
,pData);return0;}因此最終的完整程序是: //程序開始#include<stdio.h>#include<string.h>typedefunsignedlongULONG;/*初始化函數*/voidrc4_init(unsignedchar*s,unsignedchar*key,unsignedlongLen){inti=0,j=0;chark[256]={0};unsignedchartmp=0;for(i=0;i<256;i++){s[i]=i;k[i]=key[i%Len];}for(i=0;i<256;i++){j=(j+s[i]+k[i])%256;tmp=s[i];s[i]=s[j];//交換s[i]和s[j]s[j]=tmp;}}/*加解密*/voidrc4_crypt(unsignedchar*s,unsignedchar*Data,unsignedlongLen){inti=0,j=0,t=0;unsignedlongk=0;unsignedchartmp;for(k=0;k<Len;k++){i=(i+1)%256;j=(j+s[i])%256;tmp=s[i];s[i]=s[j];//交換s[x]和s[y]s[j]=tmp;t=(s[i]+s[j])%256;Data[k]^=s[t];}}intmain(){unsignedchars[256]={0},s2[256]={0};//S-boxcharkey[256]={justfortest};charpData[512]=這是一個用來加密的數據Data;unsignedlonglen=strlen(pData);inti;printf(pData=%s
,pData);printf(key=%s,length=%d
,key,strlen(key));rc4_init(s,(unsignedchar*)key,strlen(key));//已經完成了初始化printf(完成對S[i]的初始化,如下:
);for(i=0;i<256;i++){printf(%02X,s[i]);if(i&&(i+1)%16==0)putchar('
');}printf(
);for(i=0;i<256;i++)//用s2[i]暫時保留經過初始化的s[i],很重要的!!!{s2[i]=s[i];}printf(已經初始化,現在加密:
);rc4_crypt(s,(unsignedchar*)pData,len);//加密printf(pData=%s
,pData);printf(已經加密,現在解密:
);//rc4_init(s,(unsignedchar*)key,strlen(key));//初始化密鑰rc4_crypt(s2,(unsignedchar*)pData,len);//解密printf(pData=%s
,pData);return0;}//程序完
⑧ RC4演算法的介紹
RC4加密演算法是大名鼎鼎的RSA三人組中的頭號人物Ron Rivest在1987年設計的密鑰長度可變的流加密演算法簇。