/**
         * @brief 메시지 덧붙이기와 길이 덧붙이기를 수행한 후 마지막 메시지 블록을 가지고 압축함수를 호출하는 함수
         * @param Info : SHA256_Init 호출하여 초기화된 구조체(내부적으로 사용된다.)
         * @param pszDigest : 암호문
         */
        public static void SHA256_Close(SHA256_INFO Info, byte[] pszDigest)
        {
            int i, Index;

            Index = Common.URShift(Info.uLowLength, 3) % SHA256_DIGEST_BLOCKLEN;
            Info.szBuffer[Index++] = (byte)0x80;

            if (Index > SHA256_DIGEST_BLOCKLEN - 8)
            {
                Common.arrayinit_offset(Info.szBuffer, Index, (byte)0, SHA256_DIGEST_BLOCKLEN - Index);
                SHA256_Transform(Info.szBuffer, Info.uChainVar);
                Common.arrayinit(Info.szBuffer, (byte)0, SHA256_DIGEST_BLOCKLEN - 8);
            }
            else
            {
                Common.arrayinit_offset(Info.szBuffer, Index, (byte)0, SHA256_DIGEST_BLOCKLEN - Index - 8);
            }

            if (ENDIAN == Common.LITTLE_ENDIAN)
            {
                Info.uLowLength  = ENDIAN_REVERSE_ULONG(Info.uLowLength);
                Info.uHighLength = ENDIAN_REVERSE_ULONG(Info.uHighLength);
            }

            Common.int_to_byte_unit(Info.szBuffer, ((int)(SHA256_DIGEST_BLOCKLEN / 4 - 2)) * 4, Info.uHighLength, ENDIAN);
            Common.int_to_byte_unit(Info.szBuffer, ((int)(SHA256_DIGEST_BLOCKLEN / 4 - 1)) * 4, Info.uLowLength, ENDIAN);

            SHA256_Transform(Info.szBuffer, Info.uChainVar);

            for (i = 0; i < SHA256_DIGEST_VALUELEN; i += 4)
            {
                BIG_D2B((Info.uChainVar)[i / 4], pszDigest, i);
            }
        }
        /**
         * @brief 사용자 입력 평문을 한번에 처리
         * @param pszMessage : 사용자 입력 평문
         * @param pszDigest : 암호문
         * @remarks 내부적으로 SHA256_Init, SHA256_Process, SHA256_Close를 호출한다.
         */
        public static void SHA256_Encrpyt(byte[] pszMessage, int uPlainTextLen, byte[] pszDigest)
        {
            SHA256_INFO info = new SHA256_INFO();

            SHA256_Init(info);
            SHA256_Process(info, pszMessage, uPlainTextLen);
            SHA256_Close(info, pszDigest);
        }
        /**
         * @brief 연쇄변수와 길이변수를 초기화하는 함수
         * @param Info : SHA256_Process 호출 시 사용되는 구조체
         */
        public static void SHA256_Init(SHA256_INFO Info)
        {
            Info.uChainVar[0] = 0x6a09e667;
            Info.uChainVar[1] = unchecked ((int)(0xbb67ae85));
            Info.uChainVar[2] = 0x3c6ef372;
            Info.uChainVar[3] = unchecked ((int)(0xa54ff53a));
            Info.uChainVar[4] = 0x510e527f;
            Info.uChainVar[5] = unchecked ((int)(0x9b05688c));
            Info.uChainVar[6] = 0x1f83d9ab;
            Info.uChainVar[7] = 0x5be0cd19;

            Info.uHighLength = Info.uLowLength = 0;
        }
        /**
         * @brief 연쇄변수와 길이변수를 초기화하는 함수
         * @param Info : SHA256_Init 호출하여 초기화된 구조체(내부적으로 사용된다.)
         * @param pszMessage : 사용자 입력 평문
         * @param inLen : 사용자 입력 평문 길이
         */
        public static void SHA256_Process(SHA256_INFO Info, byte[] pszMessage, int uDataLen)
        {
            int pszMessage_offset;

            if ((Info.uLowLength += (uDataLen << 3)) < 0)
            {
                Info.uHighLength++;
            }

            Info.uHighLength += Common.URShift(uDataLen, 29);

            pszMessage_offset = 0;
            while (uDataLen >= SHA256_DIGEST_BLOCKLEN)
            {
                Common.arraycopy_offset(Info.szBuffer, 0, pszMessage, pszMessage_offset, SHA256_DIGEST_BLOCKLEN);
                SHA256_Transform(Info.szBuffer, Info.uChainVar);
                pszMessage_offset += SHA256_DIGEST_BLOCKLEN;
                uDataLen          -= SHA256_DIGEST_BLOCKLEN;
            }

            Common.arraycopy_offset(Info.szBuffer, 0, pszMessage, pszMessage_offset, uDataLen);
        }