糊言亂語(yǔ)

          志未半斤, 才無(wú)八兩. 有苦有樂(lè), 糊涂過(guò)活。
          posts - 25, comments - 7, trackbacks - 0, articles - 42
            BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

          2007年12月5日

          image

          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ǔ)碼

        1. 原碼
          將最高位作為符號(hào)位(以0代表正,1代表負(fù)),其余各位代表數(shù)值本身的絕對(duì)值(以二進(jìn)制表示)。
                      為了簡(jiǎn)單起見(jiàn),我們用1個(gè)字節(jié)來(lái)表示一個(gè)整數(shù)。
                      +7的原碼為: 00000111
                       -7的原碼為: 10000111
        2. 反碼
                一個(gè)數(shù)如果為正,則它的反碼與原碼相同;一個(gè)數(shù)如果為負(fù),則符號(hào)位為1,其余各位是對(duì)原碼取反。
                      為了簡(jiǎn)單起見(jiàn),我們用1個(gè)字節(jié)來(lái)表示一個(gè)整數(shù)。
                      +7的反碼為: 00000111
                       -7的反碼為: 11111000
        3. 補(bǔ)碼
              利用溢出,我們可以將減法變成加法。
              對(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。
        4.  

          那么我們就知道了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)算操作

        5. 位運(yùn)算符
          為了方便對(duì)二進(jìn)制位進(jìn)行操作,Java給我們提供了四個(gè)二進(jìn)制位操作符:
          &          按位與
          |           按位或
          ^          按位異或
          ~          按位取反
        6. 按位
              一個(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。
        7. 按位
              一個(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。
        8. 按位異或
              一個(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。
        9. 按位取反
          結(jié)論:對(duì)二進(jìn)制數(shù)按位取反,即0變成1,1變成0。
        10. Java中有三個(gè)移位運(yùn)算符
          左移:<<              (相當(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
        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)編輯 收藏

          主站蜘蛛池模板: 余姚市| 长沙市| 团风县| 临潭县| 柯坪县| 米泉市| 新巴尔虎左旗| 雅安市| 儋州市| 天祝| 阿勒泰市| 盐池县| 元阳县| 无为县| 拜泉县| 类乌齐县| 万载县| 靖州| 金华市| 岳普湖县| 邳州市| 定日县| 徐水县| 新安县| 余庆县| 桃园市| 海伦市| 亳州市| 北碚区| 沅江市| 隆子县| 马龙县| 曲松县| 金堂县| 周口市| 平顶山市| 济阳县| 睢宁县| 崇文区| 庄河市| 望谟县|