이 글은 기계 번역의 미러 문서이며, 원본 기사로 바로 이동하려면 여기를 클릭해 주세요.

보기: 16332|회답: 4

[알고리즘] SMS4 알고리즘은 대칭 블록 암호학 알고리즘입니다

[링크 복사]
게시됨 2015. 12. 8. 오후 9:49:35 | | |
이것은 블록 암호학 알고리즘이지만, 그는 다양한 것을 사용하고, 현재 인터넷에는 특정 소스 코드가 있지만, 이 코드는 여전히 일정한 연구 가치를 지니고 있습니다. 관심 있으시다면 함께 소통하고 배우실 수 있습니다. 사실 완전한 코드를 알려주는 건 의미가 없지만, 그래도 전체 코드 주소를 http://www.2cto.com/kf/201501/369374.html 에 첨부합니다
또한 S 박스가 있는데, 이는 DES 알고리즘에서 매우 중요하게 사용됩니다. 그래서 제 동료가 제안한 것은 DES 알고리즘의 S 박스를 명확히 이해하여 이 SMS4 알고리즘의 명세가 무엇을 말하는지 알 수 있다는 것입니다. 명세서는 첨부되어 있지 않습니다.





이전의:이곳은 오랫동안 업데이트되지 않은 것 같고, 앞으로도 매일 C 언어를 업데이트할 예정입니다.
다음:C 언어, 전체 버전 영상
게시됨 2015. 12. 8. 오후 10:19:05 |

SMS4 소개:

이 알고리즘은 그룹화 알고리즘입니다. 이 알고리즘은 패킷 길이 128비트, 키 길이 128비트(총 16바이트)를 가집니다. 암호화 알고리즘과 키 확장 알고리즘 모두 32라운드 비선형 반복 구조를 채택합니다. 복호화 알고리즘은 암호화 알고리즘과 동일한 구조를 가지지만, 라운드 키의 사용 순서가 반대이며, 복호화 휠 키는 암호화 휠 키의 역순입니다. SMS4의 모든 기본 클래스에서 암호화와 복호화의 기본 기능은 동일하지만, 암호화되었는지 복호화되었는지 판단하기 위해 int 타입 플래그 비트가 필요합니다.

SMS4 암호화 알고리즘 기본 사항:



공용 클래스 SMS4 {

    개인 정적 최종 정정 정체 ENCRYPT = 1;
    개인 정적 최종 정수 DECRYPT = 0;
    공개 정적 결승 정치 라운드 = 32;
    개인 정적 최종 정수 BLOCK = 16;

    개인 바이트[] Sbox = { (바이트) 0xd6, (바이트) 0x90, (바이트) 0xe9, (바이트) 0xfe,
            (바이트) 0xcc, (바이트) 0xe1, 0x3d, (바이트) 0xb7, 0x16, (바이트) 0xb6,
            0x14, (바이트) 0xc2, 0x28, (바이트) 0xfb, 0x2c, 0x05, 0x2b, 0x67,
            (바이트) 0x9a, 0x76, 0x2a, (바이트) 0xbe, 0x04, (바이트) 0xc3,
            (바이트) 0xaa, 0x44, 0x13, 0x26, 0x49, (바이트) 0x86, 0x06,
            (비트) 0x99, (바이트) 0x9c, 0x42, 0x50, (바이트) 0xf4, (바이트) 0x91,
            (바이트) 0xef, (바이트) 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43,
            (비트) 0xed, (바이트) 0xcf, (바이트) 0xac, 0x62, (바이트) 0xe4,
            (바이트) 0xb3, 0x1c, (바이트) 0xa9, (바이트) 0xc9, 0x08, (바이트) 0xe8,
            (비트) 0x95, (바이트) 0x80, (바이트) 0xdf, (바이트) 0x94, (바이트) 0xfa,
            0x75, (비트) 0x8f, 0x3f, (바이트) 0xa6, 0x47, 0x07, (바이트) 0xa7,
            (바이트) 0xfc, (바이트) 0xf3, 0x73, 0x17, (바이트) 0xba, (바이트) 0x83,
            0x59, 0x3c, 0x19, (바이트) 0xe6, (바이트) 0x85, 0x4f, (바이트) 0xa8,
            0x68, 0x6b, (바이트) 0x81, (바이트) 0xb2, 0x71, 0x64, (바이트) 0xda,
            (바이트) 0x8b, (바이트) 0xf8, (바이트) 0xeb, 0x0f, 0x4b, 0x70, 0x56,
            (바이트) 0x9d, 0x35, 0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, (바이트) 0xd1,
            (바이트) 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, (바이트) 0x87,
            (바이트) 0xd4, 0x00, 0x46, 0x57, (바이트) 0x9f, (바이트) 0xd3, 0x27,
            0x52, 0x4c, 0x36, 0x02, (바이트) 0xe7, (바이트) 0xa0, (바이트) 0xc4,
            (바이트) 0xc8, (바이트) 0x9e, (바이트) 0xea, (바이트) 0xbf, (바이트) 0x8a,
            (바이트) 0xd2, 0x40, (바이트) 0xc7, 0x38, (바이트) 0xb5, (바이트) 0xa3,
            (바이트) 0xf7, (바이트) 0xf2, (바이트) 0xce, (바이트) 0xf9, 0x61, 0x15,
            (비트) 0xa1, (바이트) 0xe0, (바이트) 0xae, 0x5d, (바이트) 0xa4,
            (바이트) 0x9b, 0x34, 0x1a, 0x55, (바이트) 0xad, (바이트) 0x93, 0x32,
            0x30, (바이트) 0xf5, (바이트) 0x8c, (바이트) 0xb1, (바이트) 0xe3, 0x1d,
            (비트) 0xf6, (바이트) 0xe2, 0x2e, (바이트) 0x82, 0x66, (바이트) 0xca,
            0x60, (비트) 0xc0, 0x29, 0x23, (바이트) 0xab, 0x0d, 0x53, 0x4e, 0x6f,
            (바이트) 0xd5, (바이트) 0xdb, 0x37, 0x45, (바이트) 0xde, (바이트) 0xfd,
            (바이트) 0x8e, 0x2f, 0x03, (바이트) 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b,
            0x51, (바이트) 0x8d, 0x1b, (바이트) 0xaf, (바이트) 0x92, (바이트) 0xbb,
            (바이트) 0xdd, (바이트) 0xbc, 0x7f, 0x11, (바이트) 0xd9, 0x5c, 0x41,
            0x1f, 0x10, 0x5a, (byte) 0xd8, 0x0a, (byte) 0xc1, 0x31,
            (바이트) 0x88, (바이트) 0xa5, (바이트) 0xcd, 0x7b, (바이트) 0xbd, 0x2d,
            0x74, (비트) 0xd0, 0x12, (바이트) 0xb8, (바이트) 0xe5, (바이트) 0xb4,
            (바이트) 0xb0, (바이트) 0x89, 0x69, (바이트) 0x97, 0x4a, 0x0c,
            (바이트) 0x96, 0x77, 0x7e, 0x65, (바이트) 0xb9, (바이트) 0xf1, 0x09,
            (비트) 0xc5, 0x6e, (바이트) 0xc6, (바이트) 0x84, 0x18, (바이트) 0xf0,
            0x7d, (비트) 0xec, 0x3a, (바이트) 0xdc, 0x4d, 0x20, 0x79,
            (바이트) 0xee, 0x5f, 0x3e, (바이트) 0xd7, (바이트) 0xcb, 0x39, 0x48 };

    개인 정수[] CK = { 0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,
            0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9, 0xe0e7eef5,
            0xfc030a11, 0x181f262d, 0x343b4249, 0x50575e65, 0x6c737a81,
            0x888f969d, 0xa4abb2b9, 0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d,
            0x141b2229, 0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
            0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209, 0x10171e25,
            0x2c333a41, 0x484f565d, 0x646b7279 };

    private int Rotl(int x, int y) {
        X << Y → x >>> (32 - Y);
    }

    private int ByteSub(int A) {
        반환 (Sbox[A >>> 24 & 0xFF] & 0xFF) << 24
                | (Sbox[A >>> 16 & 0xFF] & 0xFF) << 16
                | (Sbox[A >>> 8 & 0xFF] & 0xFF) << 8 | (Sbox[A & 0xFF] & 0xFF);
    }

    private int L1(int B) {
        B 반환 ^ Rotl(B, 2) ^ Rotl(B, 10) ^ Rotl(B, 18) ^ Rotl(B, 24);
        return B^(B<<2|B>>>30)^(B<<10|B>>>22)^(B<<18|B>>>14)^(B<<24|B>>>8);
    }

    private int L2(int B) {
        B ^ Rotl(B, 13) ^ Rotl(B, 23);
        return B^(B<<13|B>>>19)^(B<<23|B>>>9);
    }

    void SMS4Crypt(byte[] 입력, 바이트[] 출력, int[] rk) {
        지능 R, 미드, x0, x1, x2, x3;
        int[] x = 새로운 int[4];
        int[] TMP = 새로운 int[4];
        (정수: i = 0; 저는 4< 있습니다; i++) {
            tmp[0] = 입력[0 + 4 * i] & 0xff;
            tmp[1] = 입력[1 + 4 * i] & 0xff;
            tmp[2] = 입력[2 + 4 * i] & 0xff;
            tmp[3] = 입력[3 + 4 * i] & 0xff;
            x= TMP[0] << 24 | TMP[1] << 16 | TMP[2] << 8 | TMP[3];
            x=(Input[0+4*i]<<24| Input[1+4*i]<<16| 입력[2+4*i]<<8| Input[3+4*i]);
        }
        (r = 0; < 32; r += 4) {
            미드 = x[1] ^ x[2] ^ x[3] ^ rk[r + 0];
            mid = ByteSub(mid);
            x[0] = x[0] ^ L1(중간); x4

            미드 = x[2] ^ x[3] ^ x[0] ^ rk[r + 1];
            mid = ByteSub(mid);
            x[1] = x[1] ^ L1(중간); x5

            미드 = x[3] ^ x[0] ^ x[1] ^ rk[r + 2];
            mid = ByteSub(mid);
            x[2] = x[2] ^ L1(중간); x6

            미드 = x[0] ^ x[1] ^ x[2] ^ rk[r + 3];
            mid = ByteSub(mid);
            x[3] = x[3] ^ L1(중간); x7
        }

        뒷면
        (int j = 0; j < 16; j += 4) {
            Output[j] = (바이트) (x[3 - j / 4] >>> 24 & 0xFF);
            출력[j + 1] = (바이트) (x[3 - j / 4] >>> 16 & 0xFF);
            출력[j + 2] = (바이트) (x[3 - j / 4] >>> 8 & 0xFF);
            출력[j + 3] = (바이트) (x[3 - j / 4] & 0xFF);
        }
    }

    private void SMS4KeyExt(byte[] Key, int[] rk, int CryptFlag) {
        인터셉트 레드, 미드;
        int[] x = 새로운 int[4];
        int[] TMP = 새로운 int[4];
        (정수: i = 0; 저는 4< 있습니다; i++) {
            tmp[0] = 키[0 + 4 * i] & 0xFF;
            tmp[1] = 키[1 + 4 * i] & 0xff;
            tmp[2] = Key[2 + 4 * i] & 0xff;
            tmp[3] = 키[3 + 4 * i] & 0xff;
            x= TMP[0] << 24 | TMP[1] << 16 | TMP[2] << 8 | TMP[3];
            x=Key[0+4*i]<<24| Key[1+4*i]<<16| Key[2+4*i]<<8| Key[3+4*i];
        }
        x[0] ^= 0xa3b1bac6;
        x[1] ^= 0x56aa3350;
        x[2] ^= 0x677d9197;
        x[3] ^= 0xb27022dc;
        (r = 0; < 32; r += 4) {
            미드 = x[1] ^ x[2] ^ x[3] ^ CK[R + 0];
            mid = ByteSub(mid);
            rk[r + 0] = x[0] ^= L2(중간); rk0=K4

            미드 = x[2] ^ x[3] ^ x[0] ^ CK[R + 1];
            mid = ByteSub(mid);
            rk[r + 1] = x[1] ^= L2(중간); rk1=K5

            미드 = x[3] ^ x[0] ^ x[1] ^ CK[R + 2];
            mid = ByteSub(mid);
            rk[r + 2] = x[2] ^= L2(중간); rk2=K6

            미드 = x[0] ^ x[1] ^ x[2] ^ CK[R + 3];
            mid = ByteSub(mid);
            rk[r + 3] = x[3] ^= L2(중간); rk3=K7
        }

        휠 키 순서를 복호화하기: rk31, rk30,...,rk0
        만약 (CryptFlag == DECRYPT) {
            (r = 0; r < 16; r++) {
                중간 = RK[R];
                rk[r] = rk[31 - r];
                RK[31 - R] = 미드;
            }
        }
    }

    public int sms4(byte[] in, int inLen, byte[] key, byte[] out, int CryptFlag) {
        정정력 포인트 = 0;
        int[] round_key = 새로운 int[라운드];
        int[] round_key={0};
        SMS4KeyExt(키, round_key, CryptFlag);
        바이트[] 입력 = 새 비트[16];
        바이트[] 출력 = 새 바이트[16];

        while (inLen >= 블록) {
            input = Arrays.copyOfRange(in, point, point + 16);
            output=Arrays.copyOfRange(out, point, point+16);
            SMS4Crypt(입력, 출력, round_key);
            System.arraycopy(output, 0, out, point, BLOCK);
            inLen -= 블록;
            포인트 += 블록;
        }

        0을 반환;
    }
}

패키지 외부 인터페이스:

이 기본 클래스를 기반으로 주요 인터페이스는 다음과 같습니다:



개인 정적 바이트[] encode16(byte[] plain, byte[] key);
private static byte[] decode16(byte[] cipher, byte[] key);
private static byte[] encode32(byte[] plain, byte[] key);
private static byte[] decode32(byte[] cipher, byte[] key);
공용 정적 바이트[] encodeSMS4(byte[] plain, byte[] key);
공개 정적 바이트[] decodeSMS4(byte[] cipher, byte[] key);
공개 정적 문자열 디코딩SMS4toString(byte[] cipher, byte[] key);

encode16(byte[], byte[])는 16비트 평문과 16비트 키를 암호화하는 인터페이스입니다;
개인 정적 바이트[] decode16(byte[] 암호, byte[] 키): 16비트 암호문과 16비트 키를 복호화하는 인터페이스입니다;
개인 정적 바이트[] encode32(byte[] plain, byte[] 키): 32비트 평문과 16비트 키를 암호화하는 인터페이스입니다.
개인 정적 바이트[] decode32(byte[] 암호, byte[] 키): 32비트 암호문과 16비트 키를 복호화하는 인터페이스입니다.
공개 정적 바이트[] encodeSMS4(byte[] plain, byte[] 키): 이 인터페이스는 평문과 16비트 키를 무제한 바이트로 암호화합니다.
공개 정적 바이트[] 디코드SMS4(byte[] cipher, byte[] 키): 무제한 바이트 수를 가진 암호문 및 16비트 키를 복호화하는 인터페이스입니다.
공개 정적 문자열 디코딩SMS4toString(byte[] cipher, byte[] 키): 무제한 바이트의 암호문과 16비트 키를 복호화하는 인터페이스입니다.
인터페이스 방법 코드:



공용 정적 바이트[] encodeSMS4(문자열 평문, 바이트[] 키) {
        만약 (평문 == null || plaintext.equals()) {
            null을 반환;
        }
        for (int i = plaintext.getBytes().길이 % 16; 저는 16< 됩니다; i++) {
            평문 += '';
        }
        
        return SMS4.encodeSMS4(plaintext.getBytes(), 키);
    }
   
    /**
     * 무제한 평문 길이의 SMS4 암호화
     *
     * @param 평문
     * @param 키
     * @return
     */
    공개 정적 바이트[] encodeSMS4(byte[] plaintext, byte[] key) {
        byte[] 암호문 = new byte[plaintext.length];
        
        정수 k = 0;
        int plainLen = plaintext.length;
        반면 (k + 16 <= plainLen) {
            byte[] cellPlain = 새 byte[16];
            (정수: i = 0; 저는 16< 됩니다; i++) {
                셀플레인= 평문[k + i];
            }
            byte[] cellCipher = encode16(cellPlain, key);
            (정수: i = 0; 저는 cellCipher.length를 <합니다; i++) {
                암호문[k + i] = cellCipher;
            }
            
            k += 16;
        }

        암호문 반환;
    }

    /**
     * 평문 길이 제한 없는 SMS4 복호화
     *
     * @param 암호문
     * @param 키
     * @return
     */
    공개 정적 바이트[] decodeSMS4(byte[] 암호문, byte[] 키) {
        byte[] 평문 = 새로운 byte[ciphertext.length];
        
        정수 k = 0;
        int cipherLen = ciphertext.length;
        반면 (k + 16 <= cipherLen) {
            byte[] cellCipher = 새 바이트[16];
            (정수: i = 0; 저는 16< 됩니다; i++) {
                셀사이퍼= 암호문[k + i];
            }
            byte[] cellPlain = decode16(cellCipher, key);
            (정수: i = 0; 저는 cellPlain.length를 <합니다; i++) {
                평문[k + i] = cellPlain;
            }
            
            k += 16;
        }
        
        평문 반환;
    }

    /**
     * 평문 문자열을 얻기 위해 복호화함
     * @param 암호문
     * @param 키
     * @return
     */
    public static string decodeSMS4toString(byte[] 암호문, byte[] key) {
        byte[] 평문 = 새로운 byte[ciphertext.length];
        평문 = decodeSMS4(암호문, 키);
        return new String(평문);
    }

    /**
     * 16비트 평문만 암호화됩니다
     *
     * @param 평문
     * @param 키
     * @return
     */
    개인 고정 바이트[] encode16(byte[] plaintext, byte[] key) {
        byte[] 암호 = 새로운 바이트[16];
        SMS4 sm4 = 새로운 SMS4();
        sm4.sms4(평문, 16, 키, 암호, 암호화);

        반환 암호;
    }

    /**
     * 복호화되는 것은 16비트 암호문뿐입니다
     *
     * @param 평문
     * @param 키
     * @return
     */
    개인 정적 바이트[] decode16(byte[] 암호문, byte[] key) {
        byte[] plain = 새 바이트[16];
        SMS4 sm4 = 새로운 SMS4();
        sm4.sms4(암호문, 16, 키, 평범, 복호);

        평정으로 반환;
    }
여기서 32비트 평문 암호화만을 소개하지는 않겠습니다. 이는 16비트 평문 방식과 매우 유사합니다.


평문 길이를 제한하지 않고 암호화 및 복호화를 위한 기본 알고리즘은 16비트만 암호화하고 복호화하는 이 기본 기반을 기반으로 합니다. 16비트 이상의 평문에는 패킷 암호화가 사용됩니다. 만약 30비트 같은 평문이 16으로 나누어질 수 없다면, 16으로 나누어질 수 있을 때까지 채우는 방법이 있습니다. 원칙적으로는 가장 작은 숫자만 16으로 나눌 수 있습니다. 물론 행복하면 더 크게 해도 상관없습니다. 왜냐하면 그것이 마지막 기호이기 때문입니다.

패킷 암호화는 각 16비트 평문을 한 번씩 암호화한 후, 암호화된 16비트 암호문을 새로운 암호문으로 재조립하는 것입니다. 복호화 과정에서 이 문서도 단일 16비트 조각으로 분리되고, 복호화된 평문들 중 여러 개가 새로운 평문으로 재조립됩니다.



사용 시연:




        byte[] 키 = { 0x01, 0x23, 0x45, 0x67, (byte) 0x89, (byte) 0xab,
                (비트) 0xcd, (바이트) 0xef, (바이트) 0xfe, (바이트) 0xdc,
                (바이트) 0xba, (바이트) 0x98, 0x76, 0x54, 0x32, 0x10 };

        문자열 newString = 코딩, 안녕하세요!; 평문
        
        byte[] enOut = SMS4.encodeSMS4(newString, key);
        만약 (enOut == null) {
            돌아오다;
        }
        
        System.out.println(암호화 결과:);
        printBit(enOut);

        byte[] deOut = SMS4.decodeSMS4(enOut, key);
        System.out.println(
복호화 결과(반환 바이트[]) :);
        printBit(deOut);

        String deOutStr = SMS4.decodeSMS4toString(enOut, key);
        System.out.println(
결과 복호화 (문자열 반환):
+ deOutStr);
 집주인| 게시됨 2015. 12. 8. 오후 10:25:41 |
샤오 자자 2015-12-8 22:19에 게시됨
SMS4 소개:

이 알고리즘은 그룹화 알고리즘입니다. 이 알고리즘은 패킷 길이 128비트, 키 길이 128비트(총 16바이트)를 가집니다. ...

안에 있는 얼굴을 복사하는 거야? 이 알고리즘을 컴퓨터에서 여러 번 실행해봤지만, 자바 디버깅에서 C#에 익숙하지 않고, 그의 모든 단계를 자세히 알지 못할 수도 있으며, 작업 원리도 아직 파악하지 못했습니다. 자바, 모든 변수를 디버깅할 줄 아나요?
게시됨 2015. 12. 8. 오후 10:40:48 |

브레이크포인트를 설정하는 것, 즉식의 브레이크포인트 F5 키와 F6 키는 단일 단계 디버깅, F5는 스텝 인, 즉 실행할 줄 코드를 입력하는 것, F6는 스텝 오버, 즉 라인 코드를 실행하고 다음 줄로 점프하는 방식이어야 합니다
 집주인| 게시됨 2015. 12. 8. 오후 11:07:37 |
2015-12-8 22:40에 게시됨
브레이크포인트를 설정하는 것이어야 하며, 일식의 브레이크포인트 F5 키와 F6 키는 모두 단일 단계 디버깅이며, F5는 스텝 인, 즉 이 줄의 코드를 입력하여 실행해야 합니다...

저도 확실히 알고 있지만, 구체적인 절차는 모르고, 언제 어디서 사양서 단계에 도달할지 모르겠습니다. 이해해 주면 좋겠어요
면책 조항:
Code Farmer Network에서 발행하는 모든 소프트웨어, 프로그래밍 자료 또는 기사는 학습 및 연구 목적으로만 사용됩니다; 위 내용은 상업적 또는 불법적인 목적으로 사용되지 않으며, 그렇지 않으면 모든 책임이 사용자에게 부담됩니다. 이 사이트의 정보는 인터넷에서 가져온 것이며, 저작권 분쟁은 이 사이트와는 관련이 없습니다. 위 내용은 다운로드 후 24시간 이내에 컴퓨터에서 완전히 삭제해야 합니다. 프로그램이 마음에 드신다면, 진짜 소프트웨어를 지원하고, 등록을 구매하며, 더 나은 진짜 서비스를 받아주세요. 침해가 있을 경우 이메일로 연락해 주시기 바랍니다.

Mail To:help@itsvse.com