'2019/11/24'에 해당되는 글 1건

728x90

안드로이드와 PHP간에 암호화 통신을 하는 알고리즘을 찾아서 테스트를 했다.

본 게시글은 2017년도에 작성했다가 암호화 코드 부분을 바로 활용할 수 있도록 사용중인 코드를 오픈한다.


AES256Cipher.java  (2019.11.24일 수정)

import android.util.Base64;

import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.AlgorithmParameterSpec;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class AES256Cipher {
    public static byte[] ivBytes = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };


    public static String AES_Encode(String str, String key)    throws java.io.UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {

        byte[] textBytes = str.getBytes("UTF-8");
        AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivBytes);
        SecretKeySpec newKey = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
        Cipher cipher = null;
        cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, newKey, ivSpec);

        return Base64.encodeToString(cipher.doFinal(textBytes), 0);
    }

    public static String AES_Decode(String str, String key)    throws java.io.UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {

        byte[] textBytes =Base64.decode(str,0);
        //byte[] textBytes = str.getBytes("UTF-8");
        AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivBytes);
        SecretKeySpec newKey = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, newKey, ivSpec);
        return new String(cipher.doFinal(textBytes), "UTF-8");
    }

}

import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.provider.Settings;
import android.telephony.PhoneNumberUtils;
import android.telephony.TelephonyManager;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;

import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

public class Value extends AppCompatActivity {
    public static final String APKNAME = "ABC.apk"; // APK name
    public static final String IPADDRESS = "http://100.100.100.100/"; // SERVER IP (수정 요)
    private static String key = "abcdefghijkltuz12
mnopqrs34vwxy56"; // AES 암호화  키(수정 요)

    // key 대신에 AES256Key 라고 적을 수도 있다.


    // 암호화
    public static String encrypt(String data) {
        try {
            data = AES256Cipher.AES_Encode(data, Value.key);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (InvalidAlgorithmParameterException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        }
        return data;
    }

    // 복호화
    public static String decrypt(String data) {
        try {
            data = AES256Cipher.AES_Decode(data, Value.key);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (InvalidAlgorithmParameterException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        }
        return data;
    }

    public static String getVersionName(Context context) {
        PackageInfo packageInfo = null;
        try {
            packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }

        int versionCode = packageInfo.versionCode;
        String versionName = packageInfo.versionName;
        return versionName;
    }
   
}


Login.java 파일 내용 전체를 참고하려면 http://link2me.tistory.com/1230 보면 된다.

로그인 기본 정보를 안드로이드폰에 저장하고 다음부터 로그인할 때에는 저장된 로그인 정보를 이용하여 자동 로그인처리를 하도록 구현한다.


 === Login.java ===

// 전달할 인자들
params[0] = AES256Cipher.AES_Encode(params[0], Value.AES256Key);
params[1] = AES256Cipher.AES_Encode(params[1], Value.AES256Key);

Uri.Builder builder = new Uri.Builder()
        .appendQueryParameter("loginID", params[0])
        .appendQueryParameter("loginPW", params[1])
        .appendQueryParameter("deviceID", getDeviceID)
        .appendQueryParameter("tokenID", getToken);
String urlParameters = builder.build().getEncodedQuery();


 === PHP loginChk.php ===

 <?php
if(!isset($_SESSION)) {
    session_start();
}

@extract($_POST); // POST 전송으로 전달받은 값 처리
if(isset($loginID) && !empty($loginID) && isset($loginPW) && !empty($loginPW)) {

    $deviceID = $deviceID ? $deviceID : '';

    if(isset($deviceID) && !empty($deviceID)){ // 모바일 접속이면
        require_once 'db.info.php';
        require_once 'phpclass/dbClass.php';
        $conn=new MySQLiDbClass();
        $dbconn = $conn->isConnectDb($DB); // 안드로이드폰에서는 반드시 객체로 생성해야 정상접속
        require_once 'phpclass/loginClass.php';
        $c=new LoginClass();

        $loginID=$c->AES_decrypt($loginID); // 안드로이드 암호화를 복호화
        $loginPW=$c->AES_decrypt($loginPW);

        $result = $c->MobileUserAuthCheck($loginID,$loginPW,$deviceID);
        if($result > 0 ) {
            session_save_path('./_tmp/session');

            $_SESSION['userID'] = $loginID;
            $_SESSION['userPW'] = md5($loginPW);
            $_SESSION['ip'] = $_SERVER['REMOTE_ADDR'];
            $_SESSION['ua'] = $_SERVER['HTTP_USER_AGENT'];

            // 토큰 등록 및 갱신
            if(isset($tokenID) && strlen($tokenID) > 63){
                $c->registerToken($tokenID,$loginID,$deviceID); // DB에 토큰 저장
            }
            echo 1;
        } else if($result == 0) {
            echo 0; // 로그인 정보 틀림
        } else {
            echo '-1'; // Phone mismatch
        }
    }

}
?>


AES 암호화 복호화 함수

<?php
class LoginClass {

    // AES 암호화
    function AES_encrypt($plain_text){
        global $key;
        $encryptedMessage = openssl_encrypt($plain_text, "aes-256-cbc", $key, true,str_repeat(chr(0), 16));
        return base64_encode($encryptedMessage);
    }

    // AES 복호화
    function AES_decrypt($base64_text){
        global $key;
        $decryptedMessage = openssl_decrypt(base64_decode($base64_text), "aes-256-cbc", $key, true, str_repeat(chr(0), 16));
        return $decryptedMessage;
    }


   // 다른 함수들은 생략

}


도움이 되셨다면 광고 클릭 해 주세요. 좋은 글 작성에 큰 힘이 됩니다.

출처: https://link2me.tistory.com/1110 [소소한 일상 및 업무TIP 다루기]

도움이 되셨다면 댓글 달아주세요. 좋은 글 작성에 큰 힘이 됩니다.

블로그 이미지

Link2Me

,