posted @ 2008-07-11 11:25 Stanley Sun 閱讀(335) | 評(píng)論 (0) | 編輯 收藏
眾所周知在計(jì)算機(jī)中所有的數(shù)據(jù)都是以二進(jìn)制的方式存儲(chǔ)的。不管是int,String,float等等不同的數(shù)據(jù)類型,最終都會(huì)保存為01的形式。那么為什么要使用這種方式儲(chǔ)存數(shù)據(jù)呢?
因?yàn)橛?jì)算機(jī)是一種電子設(shè)備,由復(fù)雜的電子元器件組合而成,一個(gè)電子元器件有帶電和不帶電兩種狀態(tài),通常我們將帶電狀態(tài)表示為數(shù)值1,不帶電狀態(tài)表示為數(shù)值0,多個(gè)這樣的元器件的組合可以表示更多狀態(tài),也就是可以表示更多的數(shù)據(jù),如000表示0,001表示1,010表示2,011表示3,依此類推,111表示 7,一個(gè)元器件可表示一位(bit)數(shù)據(jù),這種表示數(shù)據(jù)的方式就叫二進(jìn)制。
在實(shí)際的電子設(shè)備中,我們將8個(gè)這樣的元器件形成一個(gè)單元,這樣的單元叫一個(gè)字節(jié)(byte),一個(gè)字節(jié)能表示多少個(gè)數(shù)呢?表示數(shù)值的范圍是0-255。
一個(gè)字節(jié)由8個(gè)二進(jìn)位組成,其中最右邊的一位稱為“最低有效位”或“最低位”,最左邊的一位稱為“最高有效位”或“最高位”。每一個(gè)二進(jìn)位的值是0或1。
二進(jìn)制計(jì)數(shù)的缺點(diǎn):書寫太長(zhǎng),容易出錯(cuò),一般計(jì)算機(jī)的數(shù)據(jù)位數(shù)都是4的整數(shù)倍,所以,在計(jì)算機(jī)里通常采用16進(jìn)制計(jì)數(shù)法。用數(shù)字可以表示各種信息,計(jì)算機(jī)里只有數(shù)值,當(dāng)你在內(nèi)存中看到一個(gè)數(shù)值時(shí),這個(gè)數(shù)值可能代表各種意義,生活中的數(shù)值也可以代表其他意義,如1234可以代表密碼,存款額,電報(bào)信息,根據(jù)上下線索,我們就能夠知道這數(shù)值代表的意義
但是在Java中到底是如何去保存數(shù)據(jù)的呢?下面我就以int數(shù)據(jù)類型為例說(shuō)明Java的方式。
大家都知道在Java中規(guī)定1 int = 4 byte, 1 byte = 8 bit。以此推理那么1個(gè)int在計(jì)算機(jī)中就是以4 * 8 = 32位(bit)的方式存儲(chǔ)的。而又由于java中的int是屬于有符號(hào)類型(Java中不存在unsigned類型),所以32位的高一位是符號(hào)位,由此可以推理出int的儲(chǔ)存大小區(qū)間
Integer.MAX_VALUE = 2147483647(十進(jìn)制) = 1111111 11111111 11111111 11111111(二進(jìn)制)
Integer.MIN_VALUE = -2147483648(十進(jìn)制) = 10000000 00000000 00000000 00000000(二進(jìn)制)
現(xiàn)在我們知道了二進(jìn)制的概念了,但是其實(shí)二進(jìn)制我想我們想象的那么單純的表示的,他們是不同的表現(xiàn)方式如:原碼,反碼,補(bǔ)碼
將最高位作為符號(hào)位(以0代表正,1代表負(fù)),其余各位代表數(shù)值本身的絕對(duì)值(以二進(jìn)制表示)。
為了簡(jiǎn)單起見(jiàn),我們用1個(gè)字節(jié)來(lái)表示一個(gè)整數(shù)。
+7的原碼為: 00000111
-7的原碼為: 10000111
一個(gè)數(shù)如果為正,則它的反碼與原碼相同;一個(gè)數(shù)如果為負(fù),則符號(hào)位為1,其余各位是對(duì)原碼取反。
為了簡(jiǎn)單起見(jiàn),我們用1個(gè)字節(jié)來(lái)表示一個(gè)整數(shù)。
+7的反碼為: 00000111
-7的反碼為: 11111000
利用溢出,我們可以將減法變成加法。
對(duì)于十進(jìn)制數(shù),如果從9得到結(jié)果5,可以用減法:
9-4=5
因?yàn)?+6=10,我們將6作為4的補(bǔ)數(shù),將上式的減法改寫為加法:
9+6=15
去掉高位1(也就是減去10),得到結(jié)果5。
對(duì)于16進(jìn)制數(shù),如果從C得到結(jié)果5,可以用減法:
C-7=5
因?yàn)?+9=16,我們將9作為7的補(bǔ)數(shù),將上式的減法改寫為加法:
C+9=15
去掉高位1(也就是減去16),得到結(jié)果5。
在計(jì)算機(jī)中,如果我們用1個(gè)字節(jié)表示一個(gè)數(shù),一個(gè)字節(jié)有8位,超過(guò)8位就進(jìn)1,在內(nèi)存中情況為:
1 00000000
進(jìn)位1被丟棄。
一個(gè)數(shù)如果為正,則它的原碼、反碼、補(bǔ)碼相同;一個(gè)數(shù)如果為負(fù),則符號(hào)位為1,其余各位是對(duì)原碼取反,然后整個(gè)數(shù)加1。
為了簡(jiǎn)單起見(jiàn),我們用1個(gè)字節(jié)來(lái)表示一個(gè)整數(shù)。
+7的補(bǔ)碼為: 00000111
-7的補(bǔ)碼為:第一步:11111000 (符號(hào)位為,其余各位取反)
第二步:11111001 (整個(gè)數(shù)加1)
+0的補(bǔ)碼:00000000;
-0的補(bǔ)碼:11111111;(第一步)
100000000;(第二步)
已知一個(gè)負(fù)數(shù)的補(bǔ)碼,將其轉(zhuǎn)換為十進(jìn)制數(shù),步驟:
1、先對(duì)各位取反;
2、將其轉(zhuǎn)換為十進(jìn)制數(shù);
3、加上負(fù)號(hào),再減去1。
例如:
11111010,最高位為1,是負(fù)數(shù),先對(duì)各位取反得00000101,轉(zhuǎn)換為十進(jìn)制數(shù)得5,加上負(fù)號(hào)得-5,再減1得-6。
那么我們就知道了1與-1的二進(jìn)制形式分別為0000000 00000000 00000000 00000001和11111111 11111111 11111111 11111111(Java中的數(shù)據(jù)是以補(bǔ)碼的形式儲(chǔ)存的)了。那么現(xiàn)在我們知道了數(shù)據(jù)是如何儲(chǔ)存的了。那么計(jì)算機(jī)是如何利用這些數(shù)據(jù)進(jìn)行計(jì)算的呢?我們知道在計(jì)算機(jī)的CPU中只有一個(gè)加法器,所有的運(yùn)算都是需要它進(jìn)行的。所以在計(jì)算機(jī)里所有的加減乘除都是轉(zhuǎn)換成加法來(lái)進(jìn)行運(yùn)算的。那么它們是怎么轉(zhuǎn)換的呢?下面我們介紹一下二進(jìn)制的運(yùn)算操作
為了方便對(duì)二進(jìn)制位進(jìn)行操作,Java給我們提供了四個(gè)二進(jìn)制位操作符:
& 按位與
| 按位或
^ 按位異或
~ 按位取反
一個(gè)房間里有兩個(gè)開(kāi)關(guān)控制房間的燈的明暗。當(dāng)兩個(gè)開(kāi)關(guān)同時(shí)處于打開(kāi)狀態(tài)時(shí),燈才能亮。
開(kāi)關(guān)1 開(kāi)關(guān)2 燈的狀態(tài)
關(guān) 關(guān) 暗
開(kāi) 關(guān) 暗
關(guān) 開(kāi) 暗
開(kāi) 開(kāi) 亮
結(jié)論:按位與,只有壹(1)壹(1)為1。
一個(gè)房間里有兩個(gè)開(kāi)關(guān)控制房間的燈的明暗。當(dāng)任何一個(gè)開(kāi)關(guān)處于打開(kāi)狀態(tài)時(shí),燈就能亮。
開(kāi)關(guān)1 開(kāi)關(guān)2 燈的狀態(tài)
關(guān) 關(guān) 暗
開(kāi) 關(guān) 亮
關(guān) 開(kāi) 亮
開(kāi) 開(kāi) 亮
結(jié)論:按位或,只有零(0)零(0)為0。
一個(gè)房間里有兩個(gè)開(kāi)關(guān)控制房間的燈的明暗。當(dāng)兩個(gè)開(kāi)關(guān)處于不同狀態(tài)時(shí),燈就能亮。
開(kāi)關(guān)1 開(kāi)關(guān)2 燈的狀態(tài)
關(guān) 關(guān) 暗
開(kāi) 關(guān) 亮
關(guān) 開(kāi) 亮
開(kāi) 開(kāi) 暗
結(jié)論:按位異或,只有零(0)壹(1)或壹(1)零(0)為1。
結(jié)論:對(duì)二進(jìn)制數(shù)按位取反,即0變成1,1變成0。
左移:<< (相當(dāng)于 乘以2)
帶符號(hào)右移:>> (相當(dāng)于 除以2)
無(wú)符號(hào)右移:>>>
數(shù) x x<<2 x>>2 x>>>2
17 00010001 00 01000100 00000100 01 00000100 01
-17 11101111 11 10111100 11111011 11 00111011 11
posted @ 2008-06-14 15:25 Stanley Sun 閱讀(1071) | 評(píng)論 (0) | 編輯 收藏
概念:
1.數(shù)字摘要:解決在安全的通信環(huán)境下,保證信息的唯一的一種方式。通常使用MD5/SHA-1等算法完成摘要。一般比如大家在網(wǎng)上下載軟件光盤時(shí)都會(huì)看到一個(gè)MD5值就是起到這個(gè)數(shù)字摘要的作用。在網(wǎng)絡(luò)的環(huán)境中發(fā)送者把消息和數(shù)字摘要一同發(fā)送給接收者,接收者使用發(fā)送者相同的算法對(duì)消息加密,看是否與發(fā)送者發(fā)送過(guò)來(lái)的數(shù)字摘要相同,如果相同就證明消息沒(méi)有給篡改過(guò)。下面是一個(gè)最為簡(jiǎn)單的示例:
import java.security.*; public class myDigest { public static void main(String[] args) { myDigest my=new myDigest(); my.testDigest(); } public void testDigest() { try { String myinfo="我的測(cè)試信息"; //java.security.MessageDigest alg=java.security.MessageDigest.getInstance("MD5"); java.security.MessageDigest alga=java.security.MessageDigest.getInstance("SHA-1"); alga.update(myinfo.getBytes()); byte[] digesta=alga.digest(); System.out.println("本信息摘要是:"+byte2hex(digesta)); //通過(guò)某中方式傳給其他人你的信息(myinfo)和摘要(digesta) 對(duì)方可以判斷是否更改或傳輸正常 java.security.MessageDigest algb=java.security.MessageDigest.getInstance("SHA-1"); algb.update(myinfo.getBytes()); if (algb.isEqual(digesta,algb.digest())) { System.out.println("信息檢查正常"); } else { System.out.println("摘要不相同"); } } catch (java.security.NoSuchAlgorithmException ex) { System.out.println("非法摘要算法"); } } public String byte2hex(byte[] b) //二行制轉(zhuǎn)字符串 { String hs=""; String stmp=""; for (int n=0;n<b.length;n++) { stmp=(java.lang.Integer.toHexString(b[n] & 0XFF)); if (stmp.length()==1) hs=hs+"0"+stmp; else hs=hs+stmp; if (n<b.length-1) hs=hs+":"; } return hs.toUpperCase(); } }
2.電子簽名:對(duì)數(shù)據(jù)信息的發(fā)生者身份的認(rèn)定,它是一種抽象的概念而不是一種具體技術(shù)。實(shí)現(xiàn)電子簽名的技術(shù)手段目前有多種,比如基于公鑰密碼技術(shù)的數(shù)字簽名;或用一個(gè)獨(dú)一無(wú)二的以生物特征統(tǒng)計(jì)學(xué)為基礎(chǔ)的識(shí)別標(biāo)識(shí),例如手印、聲音印記或視網(wǎng)膜掃描的識(shí)別;手書簽名和圖章的電子圖象的模式識(shí)別;表明身份的密碼代號(hào)(對(duì)稱算法);基于量子力學(xué)的計(jì)算機(jī)等等。
3.數(shù)字簽名:所謂數(shù)字簽名就是利用通過(guò)某種密碼運(yùn)算生成的一系列符號(hào)及代碼組成電子密碼進(jìn)行"簽名",來(lái)代替書寫簽名或印章,對(duì)于這種電子式的簽名在技術(shù)上還可進(jìn)行算法驗(yàn)證,其驗(yàn)證的準(zhǔn)確度是在物理世界中與手工簽名和圖章的驗(yàn)證是無(wú)法相比的。一般實(shí)現(xiàn)數(shù)字簽名的方法是通過(guò)生成的密鑰對(duì)的私鑰對(duì)用戶生成的數(shù)字消息進(jìn)行DSA(Digital Signature Algorithm (DSA)是Schnorr和ElGamal簽名算法的變種,被美國(guó)NIST作為DSS(DigitalSignature Standard))加密實(shí)現(xiàn)的。實(shí)現(xiàn)代碼如下:
*/ import java.security.*; import java.security.spec.*; public class testdsa { public static void main(String[] args) throws java.security.NoSuchAlgorithmException,java.lang.Exception { testdsa my=new testdsa(); my.run(); } public void run() { //數(shù)字簽名生成密鑰 //第一步生成密鑰對(duì),如果已經(jīng)生成過(guò),本過(guò)程就可以跳過(guò),對(duì)用戶來(lái)講myprikey.dat要保存在本地 //而mypubkey.dat給發(fā)布給其它用戶 if ((new java.io.File("myprikey.dat")).exists()==false) { if (generatekey()==false) { System.out.println("生成密鑰對(duì)敗"); return; }; } //第二步,此用戶 //從文件中讀入私鑰,對(duì)一個(gè)字符串進(jìn)行簽名后保存在一個(gè)文件(myinfo.dat)中 //并且再把myinfo.dat發(fā)送出去 //為了方便數(shù)字簽名也放進(jìn)了myifno.dat文件中,當(dāng)然也可分別發(fā)送 try { java.io.ObjectInputStream in=new java.io.ObjectInputStream(new java.io.FileInputStream("myprikey.dat")); PrivateKey myprikey=(PrivateKey)in.readObject(); in.close(); // java.security.spec.X509EncodedKeySpec pubX509=new java.security.spec.X509EncodedKeySpec(bX509); //java.security.spec.X509EncodedKeySpec pubkeyEncode=java.security.spec.X509EncodedKeySpec String myinfo="這是我的信息"; //要簽名的信息 //用私鑰對(duì)信息生成數(shù)字簽名 java.security.Signature signet=java.security.Signature.getInstance("DSA"); signet.initSign(myprikey); signet.update(myinfo.getBytes()); byte[] signed=signet.sign(); //對(duì)信息的數(shù)字簽名 System.out.println("signed(簽名內(nèi)容)="+byte2hex(signed)); //把信息和數(shù)字簽名保存在一個(gè)文件中 java.io.ObjectOutputStream out=new java.io.ObjectOutputStream(new java.io.FileOutputStream("myinfo.dat")); out.writeObject(myinfo); out.writeObject(signed); out.close(); System.out.println("簽名并生成文件成功"); } catch (java.lang.Exception e) { e.printStackTrace(); System.out.println("簽名并生成文件失敗"); }; //第三步 //其他人通過(guò)公共方式得到此戶的公鑰和文件 //其他人用此戶的公鑰,對(duì)文件進(jìn)行檢查,如果成功說(shuō)明是此用戶發(fā)布的信息. // try { java.io.ObjectInputStream in=new java.io.ObjectInputStream(new java.io.FileInputStream("mypubkey.dat")); PublicKey pubkey=(PublicKey)in.readObject(); in.close(); System.out.println(pubkey.getFormat()); in=new java.io.ObjectInputStream(new java.io.FileInputStream("myinfo.dat")); String info=(String)in.readObject(); byte[] signed=(byte[])in.readObject(); in.close(); java.security.Signature signetcheck=java.security.Signature.getInstance("DSA"); signetcheck.initVerify(pubkey); signetcheck.update(info.getBytes()); if (signetcheck.verify(signed)) { System.out.println("info="+info); System.out.println("簽名正常"); } else System.out.println("非簽名正常"); } catch (java.lang.Exception e) {e.printStackTrace();}; } //生成一對(duì)文件myprikey.dat和mypubkey.dat---私鑰和公鑰, //公鑰要用戶發(fā)送(文件,網(wǎng)絡(luò)等方法)給其它用戶,私鑰保存在本地 public boolean generatekey() { try { java.security.KeyPairGenerator keygen=java.security.KeyPairGenerator.getInstance("DSA"); // SecureRandom secrand=new SecureRandom(); // secrand.setSeed("tttt".getBytes()); //初始化隨機(jī)產(chǎn)生器 // keygen.initialize(576,secrand); //初始化密鑰生成器 keygen.initialize(512); KeyPair keys=keygen.genKeyPair(); // KeyPair keys=keygen.generateKeyPair(); //生成密鑰組 PublicKey pubkey=keys.getPublic(); PrivateKey prikey=keys.getPrivate(); java.io.ObjectOutputStream out=new java.io.ObjectOutputStream(new java.io.FileOutputStream("myprikey.dat")); out.writeObject(prikey); out.close(); System.out.println("寫入對(duì)象 prikeys ok"); out=new java.io.ObjectOutputStream(new java.io.FileOutputStream("mypubkey.dat")); out.writeObject(pubkey); out.close(); System.out.println("寫入對(duì)象 pubkeys ok"); System.out.println("生成密鑰對(duì)成功"); return true; } catch (java.lang.Exception e) { e.printStackTrace(); System.out.println("生成密鑰對(duì)失敗"); return false; }; } public String byte2hex(byte[] b) { String hs=""; String stmp=""; for (int n=0;n<b.length;n++) { stmp=(java.lang.Integer.toHexString(b[n] & 0XFF)); if (stmp.length()==1) hs=hs+"0"+stmp; else hs=hs+stmp; if (n<b.length-1) hs=hs+":"; } return hs.toUpperCase(); } } 把他的公鑰的信息及簽名發(fā)給其它用戶
4.PKI(公鑰基礎(chǔ)設(shè)施):
posted @ 2007-12-05 22:09 Stanley Sun 閱讀(539) | 評(píng)論 (1) | 編輯 收藏