마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

암호문을 base64로 인코딩 후 QR코드 스캔 후 인코딩 설정

0 추천

제가 QR코드가 만들어지는 부분에서

평문을 NTRU암호화->BASE64인코딩->문자열->Base64디코딩->NTRU복호화를 하였을때는 잘되었습니다.

이제 위의 단계에서 문자열을 QR코드로 만드는 부분에서는 

NTRU암호화->BASE64인코딩->문자열-> QR코드를

하였고 스캔하는 부분에선는 스캔한 문자열->Base64디코딩->NTRU복호화 하였더니 복호화한 부분에서

인코딩 방식이 다르다는 오류가 나왔습니다. 스캔과정에서 어디가 인코딩 방식을  건든지 모르겠습니다.

아래 코드는 QR코드를 만드는 과정입니다.

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_qr_create);
        ImageView qr = findViewById(R.id.QRview);

        MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
        try{
            Hashtable hints = new Hashtable();
            hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");

            TelephonyManager tm = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
            String ID = Settings.Secure.getString(this.getContentResolver(), Settings.Secure.ANDROID_ID);


            Date currentTime = new Date();
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", java.util.Locale.getDefault());
            String getTime = simpleDateFormat.format(currentTime);

            NtruEncrypt ntru = new NtruEncrypt(EncryptionParameters.APR2011_439_FAST);
            EncryptionKeyPair kp = ntru.generateKeyPair();

            byte[] enc = ntru.encrypt((getTime+ID).getBytes(), kp.getPublic());
            Log.e("enc", new String(enc) );
            String str1 = android.util.Base64.encodeToString(enc, android.util.Base64.NO_WRAP); // 일단 QR코드의 재료가 될 문자열
            Log.e("str1", str1 );
            byte[] decode = android.util.Base64.decode(str1, android.util.Base64.NO_WRAP); // base64디코딩 실험
            byte[] dec = ntru.decrypt(decode, kp); // ntru 복호화 실험
            Toast.makeText(this, new String(enc), Toast.LENGTH_SHORT).show(); // 복호화 성공을 알 수 있음


            BitMatrix bitMatrix = multiFormatWriter.encode(str1, BarcodeFormat.QR_CODE, 600, 600);
            BarcodeEncoder barcodeEncoder = new BarcodeEncoder();
            Bitmap bitmap = barcodeEncoder.createBitmap(bitMatrix);
            qr.setImageBitmap(bitmap);
        }catch (Exception e){
            e.printStackTrace();
        }

아래는 스캔하는 부분 입니다.

오류 코드는 다음과 같습니다.

net.sf.ntru.exception.NtruException: Illegal encoding!
        at net.sf.ntru.util.ArrayEncoder.encodeMod3Sves(ArrayEncoder.java:250)
        at net.sf.ntru.polynomial.IntegerPolynomial.toBinary3Sves(IntegerPolynomial.java:224)
        at net.sf.ntru.encrypt.NtruEncrypt.decrypt(NtruEncrypt.java:457)

 

허접 (160 포인트) 님이 2022년 5월 26일 질문

2개의 답변

0 추천

님이 사용하신 라이브러리들을 가지고 동작하는 예제를 만들어봤습니다. 급조한 예제로 매끄럽지 못한 부분들이 있습니다.

import android.util.Base64
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import net.sf.ntru.encrypt.EncryptionKeyPair
import net.sf.ntru.encrypt.EncryptionParameters
import net.sf.ntru.encrypt.NtruEncrypt
import net.sf.ntru.exception.NtruException
import net.sf.ntru.sign.NtruSign
import net.sf.ntru.sign.SignatureKeyPair
import net.sf.ntru.sign.SignatureParameters

class NtruCipher {
    companion object {
        private val SIGNATURE_PARAMS = SignatureParameters.APR2011_439_PROD
        private val ENCRYPTION_PARAMS = EncryptionParameters.APR2011_439_FAST
    }

    private val ntruEncrypt: NtruEncrypt by lazy { NtruEncrypt(ENCRYPTION_PARAMS) }
    private val ntruSign: NtruSign by lazy { NtruSign(SIGNATURE_PARAMS) }
    private val encKePair: EncryptionKeyPair by lazy {
        ntruEncrypt.generateKeyPair()
    }
    private val signKeyPair: SignatureKeyPair by lazy {
        SignatureKeyPair(Base64.decode(sigKPStr, Base64.DEFAULT))
    }

    suspend fun encrypt(message: String): Result<ByteArray> = withContext(Dispatchers.Default) {
        try {
            Result.success(ntruEncrypt.encrypt(message.toByteArray(), encKePair.public))
        } catch (e: CancellationException) {
            throw e
        } catch (e: NtruException) {
            Result.failure(e)
        }
    }

    suspend fun decrypt(encrypted: ByteArray): Result<ByteArray> =
        withContext(Dispatchers.Default) {
            try {
                Result.success(ntruEncrypt.decrypt(encrypted, encKePair))
            } catch (e: CancellationException) {
                throw e
            } catch (e: NtruException) {
                Result.failure(e)
            }
        }

    private suspend fun verify(message: String): Result<Boolean> =
        withContext(Dispatchers.Default) {
            val signature = ntruSign.sign(message.toByteArray(), signKeyPair)
            try {
                val verified = ntruSign.verify(message.toByteArray(), signature, signKeyPair.public)
                Result.success(verified)
            } catch (e: CancellationException) {
                throw e
            } catch (e: NtruException) {
                Result.failure(e)
            }
        }
}

const val sigKPStr =
    "AbcIAIL1Qobon5XHmjNxKglpn1C9uHRdHgdG++sRW4ujoG5gp57hVpIxqZBU/tcP7elkNLbAMrks" +
            "K2l2LHLPdfZqrfo/vVF5WwQdP8IyBpx0fcYxsvz7IGP09YORwufaTkmoY3pRn3wl9XUAzAZedXhD" +
            "S5/y9aT8TWhB6lLCSa8nTvNgtAe+W/Ru591ttP4kBtr7yLnz0+MWE82a1Fwc1ytD78qw8IXiSW0o" +
            "DYE7TZbCDHeaGR9iHw8/NbUMl0Az9E7hvdKMvlNXhSzIsxzT29P1KCW48sm0NJoRwK7nKpREbMpn" +
            "580vM8qWEd3vbh2ccB/LOn3LDAB24NQvMQM/c0gV+1gCUy9qjelPZAlCr2g6XKrj9OHcBucA0cWA" +
            "6k9Gn4T2H3/z87Jenu+I9GNHkZVW7A1GHqR+evoxrsFRYISGrHc+hDmnNgvUo6hzg8FIxFFS4VBI" +
            "YxcRxmtqr6/nYCuULHW0AQtQ7S7Qtc1F4hZ06igc9Ew2mPPbFDYCMABCdKgVCP+bzXiAmJljSLzC" +
            "2tqbI+EZHN/8lZatxCngCAt73gLpKivliJuvhY8wbVMXrpZfdDn2JVun55gKH5u4+XDWLzVfBkEg" +
            "BoM9wjWrNaTaMyHgoGpVAiiQXnnq5ul+UXzsrWaAWefR2ZQW7/o9dVwFlS3p4tmVLdaymCev8sQR" +
            "jJ1zrfPn1wmitvqeRWjmn1mI9Usvh1cw9Oq8Zsg/aSbwHqKslVMG5HJajwmVc2gOCZkh1NfHxbs1" +
            "t2EHFmVb3pYdeDE9IcZZZSBn4kU+Vk0nXqLXMcnjmYxw0TYHQwkBtwgADUeZIAACAAkACVTgxTO0" +
            "gZGaNKUthQES0IEuhjENcwgFM6EBAAgACDGwAh6kgRW7bCY0MthBIhghiV2Y5DIABgAFCBCFREQC" +
            "lrEAhxCKWhRjGwAJAAkrsIIbbOENiYiEL7UBGNgAGECRDIPoZDSlAQAIAAglcEIa4pEVsQBGMhxg" +
            "AyAsQQ1y7CMjAAYABUkAAy2AUZGTADC4Rjj6IRMACQAJJJgDUYoClba8RTOdAQK4AArocIi+COY0" +
            "sgEACAAIVRjHOwDCFbAYBjIv4EEUqJCFgGiFNAAGAAUqeEQ1sgEQjgAiiAU9EpIWAAkACQMYgi0S" +
            "shOj+GUymwEhMEM09mEQqGxlNK8BAAgACAfIgRNUkQ54jCQsH3gBH3ohkrGQhjYABgAFOnDEI+5h" +
            "lMUArkDHQiiiFyJ6FG2e0sVos6FxsWgNwouRiHOSze24MFVnXVDUq94rycpGY69uuPY7QOD6VEey" +
            "sbP6K4j508LBeUHVkSIUnfSrYlvXRHaYp2iTHuZWEZQ5HX7YSeLCDVDMb7GsfIqXSP3NSyfFO9Am" +
            "SmY6wTiUykOWPbyQP8kU2a7rOBpLNy7lQO0wR0nNUBcPKeu+thivAm5DQgv7ZSIVcz4aDKkzAqIl" +
            "9dSmI5VFBGlCf9NVtU20a3S0txGjDt7aI0EiE/96WBvS+VI3bndxK9Y+ir6Nf5wAZ9iKGZKsRJkD" +
            "9tlmERgL0w56QjQxqear5AcXCykxSzqvDnF128krEVnNGmZfWqA49H+C8NYZmJgQh9M1LUsoKUWt" +
            "4ETETj/5THBrLkTlzt8dXe3JF71hh18h/m81Vxq3GXP6mEZsblC49EPokfguATnDlpWIySZ23i+h" +
            "lI9oVHpUINNyJvp3EsffKbtT/2CC8JW6Js2L5dw/jRi754UJHDOB76Cn4IF1kaOoifD84MRtb1WA" +
            "6k2O2g1JOexXU/vnI/Yr13rcqrt7EJJCL0OVvLlSxpJLR8wqv0z91F8NGhXwzS1fVwSqcRAU6NnR" +
            "LWtGjV4NbdD1lZ1BCtC5VqCs/PXL4iXWvEW27YSJX+Dk9WCtvds/OFV07j6daRpPeehcbAYtQQ12" +
            "y62sMrvRlSakD4eEioOk/Hj2eSKbmCtswYpSdcRbaiponZv77Gf3dSWRuK1pSV9nhPp5na08X6Ta" +
            "HKvSNIz98Bt9zzT37Qvz4cVDLxUrPfVrMxYwvmTAm1ejkP6V1Kw8Kp3K4RQ="

 

package com.remind.sampleapp

import android.graphics.Bitmap
import com.google.zxing.BarcodeFormat
import com.google.zxing.MultiFormatWriter
import com.google.zxing.WriterException
import com.google.zxing.common.BitMatrix
import com.journeyapps.barcodescanner.BarcodeEncoder
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.util.concurrent.CancellationException

class QRCodeHelper {
    private val multiFormatWriter by lazy { MultiFormatWriter() }

    suspend fun generateQrCode(base64Str: String): Result<QRCode> =
        withContext(Dispatchers.Default) {
            try {
                val bitMatrix: BitMatrix =
                    multiFormatWriter.encode(base64Str, BarcodeFormat.QR_CODE, 500, 500)
                Result.success(QRCode(bitMatrix))
            } catch (e: CancellationException) {
                throw e
            } catch (e: WriterException) {
                e.printStackTrace()
                Result.failure(e)
            }
        }
}

data class QRCode(
    private val bitMatrix: BitMatrix
) {
    private val barcodeEncoder by lazy { BarcodeEncoder() }

    fun bitmap(): Bitmap = barcodeEncoder.createBitmap(bitMatrix)
}

 

import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.launch

class NtruViewModel : ViewModel() {
    private val ntruCipher by lazy { NtruCipher() }
    private val qrCodeHelper by lazy { QRCodeHelper() }

    private val stateHolder = NtruUiStateHolder()
    val uiState: LiveData<NtruUiState> get() = stateHolder.uiState

    fun encrypt(message: String) = viewModelScope.launch {
        stateHolder.postLoading(isLoading = true)
        ntruCipher.encrypt(message)
            .onSuccess { encrypted ->
                generateQrCode(message, encrypted)
            }
            .onFailure(stateHolder::postError)
    }

    private suspend fun generateQrCode(message: String, encrypted: ByteArray) {
        qrCodeHelper.generateQrCode(NtruData(encrypted).base64Encoded())
            .onSuccess { qrCode ->
                val encryptedData = EncryptedData(message = message, encrypted = encrypted, qrCode = qrCode)
                stateHolder.postEncrypted(encryptedData)
            }
            .onFailure(stateHolder::postError)
    }

    fun decrypt() = viewModelScope.launch {
        ntruCipher.decrypt(stateHolder.encryptedBytes())
            .onSuccess(stateHolder::postDecrypted)
            .onFailure(stateHolder::postError)
    }
}

 

 

spark (227,830 포인트) 님이 2022년 5월 26일 답변
0 추천
import android.util.Base64

data class NtruUiState(
    val isLoading: Boolean = false,
    val error: Throwable? = null,
    val message: String = "",
    val encrypted: NtruData = NtruData(),
    val decrypted: NtruData = NtruData(),
    val qrCode: QRCode? = null
)

class EncryptedData(
    val message: String,
    val encrypted: ByteArray,
    val qrCode: QRCode
)

@JvmInline
value class NtruData(val data: ByteArray = ByteArray(0)) {
    fun text() = String(data)

    fun base64Encoded(): String {
        return Base64.encodeToString(data, Base64.DEFAULT)//.substring(0, 20)
    }
}


import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData

class NtruUiStateHolder {

    private var state = NtruUiState()
    private val mutableUiState = MutableLiveData(state)
    val uiState: LiveData<NtruUiState> get() = mutableUiState

    fun encryptedBytes(): ByteArray {
        return state.encrypted.data
    }

    fun postEncrypted(data: EncryptedData) {
        postEncrypted(message = data.message, encrypted = data.encrypted, qrCode = data.qrCode)
    }

    private fun postEncrypted(message: String, encrypted: ByteArray, qrCode: QRCode) {
        val newState = updatedState(
            isLoading = false,
            error = null,
            message = message,
            encrypted = encrypted,
            decrypted = ByteArray(0),
            qrCode = qrCode
        )
        mutableUiState.postValue(newState)
    }

    fun postDecrypted(decrypted: ByteArray) {
        mutableUiState.postValue(
            updatedState(
                isLoading = false,
                error = null,
                decrypted = decrypted
            )
        )
    }

    private fun updatedState(
        isLoading: Boolean = state.isLoading,
        error: Throwable? = state.error,
        message: String = state.message,
        encrypted: ByteArray = state.encrypted.data,
        decrypted: ByteArray = state.decrypted.data,
        qrCode: QRCode? = state.qrCode
    ): NtruUiState {
        return state.copy(
            isLoading = isLoading,
            error = error,
            message = message,
            encrypted = NtruData(encrypted),
            decrypted = NtruData(decrypted),
            qrCode = qrCode
        ).also {
            state = it
        }
    }

    fun postError(e: Throwable) {
        mutableUiState.postValue(updatedState(error = e))
    }

    fun postLoading(isLoading: Boolean) {
        mutableUiState.postValue(updatedState(isLoading = isLoading))
    }
}

 

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isVisible
import androidx.lifecycle.ViewModelProvider
import com.remind.sampleapp.databinding.ActivityNtruBinding

class NtruActivity : AppCompatActivity() {
    private val viewModel: NtruViewModel by lazy { ViewModelProvider(this)[NtruViewModel::class.java] }
    private val binding by lazy { ActivityNtruBinding.inflate(layoutInflater) }

    private val msg: String
        get() = binding.messageEdt.text.toString()

    /** Called when the activity is first created.  */
    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)

        setupView()
        observeUiState()
    }

    private fun setupView() {
        binding.apply {
            encryptBtn.setOnClickListener {
                runEncryption()
            }

            decryptBtn.setOnClickListener {
                runDecryption()
            }
        }
    }

    private fun observeUiState() {
        viewModel.uiState.observe(this, ::updateUi)
    }

    private fun updateUi(state: NtruUiState) {
        bindLoading(state.isLoading)
        bindError(state.error)
        bindEncryptedData(state)
    }

    private fun bindLoading(loading: Boolean) {
        binding.progressBar.isVisible = loading
    }

    private fun bindError(error: Throwable?) {
        error ?: return
        binding.encryptTxt.text = error.localizedMessage
    }

    private fun bindEncryptedData(state: NtruUiState) {
        if (state.message.isBlank()) return

        binding.apply {
            encryptTxt.text = state.encrypted.base64Encoded()
            decryptTxt.text = state.decrypted.text()
        }
        bindQrCode(state.qrCode)
    }

    private fun bindQrCode(qrCode: QRCode?) {
        qrCode ?: return
        binding.qrcodeImg.setImageBitmap(qrCode.bitmap())
    }

    private fun runEncryption() {
        viewModel.encrypt(msg)
    }

    private fun runDecryption() {
        viewModel.decrypt()
    }
}

도움이 되시길...

spark (227,830 포인트) 님이 2022년 5월 26일 답변
답변 감사합니다. 혹시 실례가 안된다면
코틀린을 자바로 변환해 주실 수 있나요?
자바로 변환하려면 async처리 때문에 시간이 좀 걸려요. 오늘 시간이 되면 자바버전 작업을 해볼게요.
Github에 자바버전 올려놨습니다.
https://github.com/krpot/AndroidDemoApp/tree/develop
...