<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های حسین خیراله پور</title>
        <link>https://virgool.io/feed/@h_kheirollahpour</link>
        <description>Senior Android Engineer at blu Bank</description>
        <language>fa</language>
        <pubDate>2026-06-18 05:20:35</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/2920860/avatar/rFHfI6.jpg?height=120&amp;width=120</url>
            <title>حسین خیراله پور</title>
            <link>https://virgool.io/@h_kheirollahpour</link>
        </image>

                    <item>
                <title>پیاده سازی احراز هویت با JWT در اندروید(بدون استفاده از کتابخانه)</title>
                <link>https://virgool.io/@h_kheirollahpour/%D9%BE%DB%8C%D8%A7%D8%AF%D9%87-%D8%B3%D8%A7%D8%B2%DB%8C-%D8%A7%D8%AD%D8%B1%D8%A7%D8%B2-%D9%87%D9%88%DB%8C%D8%AA-%D8%A8%D8%A7-jwt-%D8%AF%D8%B1-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%D8%A8%D8%AF%D9%88%D9%86-%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-%DA%A9%D8%AA%D8%A7%D8%A8%D8%AE%D8%A7%D9%86%D9%87-d8dznhc14isz</link>
                <description>سلام سلااااامامیدوارم حالتون خوب باشه ... امروز میخوام نحوه پیاده سازی JWT در اندروید رو بدون استفاده از کتابخونه جانبی بهتون آموزش بدم .همونطور که میدونید کتابخونه های زیادی برای استفاده از JWT وجود داره؛ ولی چون از یه استانداردی پیروی میکنه طبعا پیاده سازی اون ثابت هست و نیاز به استفاده از کتابخونه و بروزرسانی های بعدش نیست. مزیت بعدی اینه که از اضافه کردن dependency به پروژه تون جلوگیری میکنه و در نهایت دید عمیق تری نسبت به این موضوع پیدا خواهید کرد.در ابتدا یه توضیح مختصری راجع به ساختار JWT به شما میدم و بعدش میرم سراغ پیاده سازی عملی اون تو اندروید. تمامی سورس کدها در این لینک GitHub موجود هست.(لینک داکیومنت رسمی) جیسان وب توکن یا JWT چیست ؟مخفف Json Web Token می باشد که در واقع یک استاندارد و مکانیزم احراز هویت توی وب سایت ها و نرم افزارها هست. از سه بخش اصلی Header, Payload, Signature تشکیل شده:بخش Header: حاوی اطلاعاتی بصورت جیسان بیس۶۴ انکد شده که درباره نوع توکن (معمولاً JWT) و الگوریتم رمزنگاری مورد استفاده (مانند HS256 یا RS256) است. شامل: نوع الگوریتم با کلید alg؛ نوع محتوا با کلید cty؛ نوع توکن با کلید typ و شناسه کلید با کلید kid می باشد.بخش Payload: این بخش حاوی ادعاها (claims) است که اطلاعاتی به صورت جیسان بیس۶۴ انکد شده که درباره کاربر یا دیگر موارد مورد نیاز برای احراز هویت را فراهم می‌کند. این اطلاعات می‌توانند شامل شناسه کاربر، نام کاربری، تاریخ انقضای توکن و غیره باشند.حاوی اطلاعاتی درباره نوع توکن (معمولاً JWT) و الگوریتم رمزنگاری مورد استفاده (مانند HS256 یا RS256) است. شامل: صادر کننده توکن با کلید iss؛ موضوع توکن با کلید sub؛ مخاطب توکن با کلید aud؛ زمان انقضای توکن به ثانیه با کلید exp؛ زمانی که قبل از نباید توکن پذیرفته بشه به ثانیه با کلید nbf؛ زمانی که توکن صادر شده به ثانیه با کلید iat؛ شناسه منحصر به فرد توکن با کلید jti می باشد.بخش Signature: این بخش با استفاده از الگوریتم مشخص شده در Header و یک کلید مخفی (در الگوریتم‌های مبتنی بر HMAC) یا یک جفت کلید عمومی/خصوصی (در الگوریتم‌های مبتنی بر RSA یا ECDSA) ایجاد می‌شود. امضای توکن اطمینان می‌دهد که پیام تغییر نکرده و از منبع معتبر است. که به زبان ساده مقدار رمز شده عبارت (header.payload) هست.درنهایت ساختار یکپارچه و کامل یه توکن JWT بصورت زیر هست:val jwt = &quot;$header.$payload.$signature&quot;سناریوی ما چیه ؟فرض کنید که ما میخواییم بین کلاینت اندروید و سرور یه احراز هویتی صورت بگیره. به این صورت که ما یه جفت کلید ایجاد میکنیم و کلید عمومی رو به سرور ارسال میکنیم. تو یه درخواست دیگه سرور به ما یه سری اطلاعات رو ارسال میکنه که ما با استفاده از اونا توکن JWT رو ایجاد میکنیم و با استفاده از کلید خصوصی ایجاد شده تو مرحله اول رمزنگاری بخش Signature رو تولید میکنیم و درنهایت توکن کامل ایجاد شده رو برای سرور میفرستیم و از اون طرف میتونه بخش Signature و (Header.Payload) رو با کلید عمومی که قبلا براش ارسال شده Verify کنه و احراز هویت مورد تایید قرار بگیره.بریم سراغ پیاده سازی :)۱.تولید کلید: الگوریتم انتخابی ما برای رمزنگاری بخش سوم یا signature ؛ elliptic curve با طول کلید ۲۵۶ هست که تو استاندارد به اسم ES256 شناخته میشه. کلید عمومی رو به سرور میفرستیم و کلید خصوصی رو برای رمزنگاری مرحله ۴ نگه میداریم. کد نحوه تولید کلید بصورت زیر هست.val keyPairGenerator = KeyPairGenerator.getInstance(&amp;quotEC&amp;quot)
keyPairGenerator.initialize(ECGenParameterSpec(&amp;quotsecp256r1&amp;quot))
val keyPair = keyPairGenerator.generateKeyPair()
val publicKey = keyPair.public as ECPublicKey // Send to server
val privateKey = keyPair.private as ECPrivateKey // Use for signing in step 4۲. تولید Claims: ما برای تولید header و payload از ویژگی های زیر استفاده میکنیم.val header = JwtHeaderBuilder().run {
    algorithm(&amp;quotES256&amp;quot) // elliptic curve with key size 256
    type(&amp;quotJWT&amp;quot) // Needed
    contentType(&amp;quotapplication/json&amp;quot) // Optional
    keyId(&amp;quotUniqueKeyId&amp;quot) // Optional
}.build()val currentTime = System.currentTimeMillis() / 1000 // current time in seconds
val payload = JwtPayloadBuilder().run {
    issuer(&amp;quotHossein KheirollahPour&amp;quot)
    subject(&amp;quotPayment&amp;quot)
    audience(&amp;quothttps://blubank.com&amp;quot)
    issuedAt(currentTime)
    notBefore(currentTime)
    expirationTime(currentTime + 3600)// Expires after 1 hour
    jwtID(&amp;quotUniqueJwtId1234&amp;quot)
}.build()۳. آماده سازی داده از جیسان header , payload: ما تو این بخش جیسان هر بخش رو به بیس۶۴ انکد میکنیم و در نهایت اونها رو باهم ترکیب میکنیم و داده نهایی برای رمزنگاری مرحله بعد رو آماده میکنیم.val headerBytes = Base64.getUrlEncoder().withoutPadding().encodeToString(header.toByteArray(StandardCharsets.UTF_8)).toByteArray(StandardCharsets.UTF_8)
val payloadBytes = Base64.getUrlEncoder().withoutPadding().encodeToString(payload.toByteArray(StandardCharsets.UTF_8)).toByteArray(StandardCharsets.UTF_8)
val contentBytes = ByteArray(headerBytes.size + 1 + payloadBytes.size)
System.arraycopy(headerBytes, 0, contentBytes, 0, headerBytes.size)
contentBytes[headerBytes.size] = &#039;.&#039;.code.toByte()
System.arraycopy(payloadBytes, 0, contentBytes, headerBytes.size + 1, payloadBytes.size)۴. آماده سازی داده signature: در این بخش ما با استفاده از الگوریتم SHA256ECDSA و کلید خصوصی ایجاد شده تو مرحله اول؛ داده مرحله قبل رو ساین میکنیم.نکته: در نهایت که داده رو آماده کردیم با استفاده از فانکشن DERToJOSE به فرمت درست تبدیل میکنیم که برای جلوگیری از طولانی شدن کدها اینجا قید نکردم ولی داخل این بخش سورس کد موجود هست.val signatureInstance = Signature.getInstance(&amp;quotSHA256withECDSA&amp;quot)
signatureInstance.initSign(privateKey)
signatureInstance.update(contentBytes)
val  signatureBytes = signatureInstance.sign()

val convertedSignatureBytes = DERToJOSE(signatureBytes) // This function exist in source code
val signature = Base64.getUrlEncoder().withoutPadding().encodeToString(convertedSignatureBytes)۵. ساخت توکن نهایی: در این بخش داده های تولید شده توی مراحل قبل به هم متصل میشن.val jwt = String.format(&amp;quot%s.%s.%s&amp;quot, header, payload, signature)خیلی عالی شد .. بالاخره توکن JWT نهایی رو ساختیم :)در نهایت شما میتونید با استفاده از کد زیر کلید عمومی خودتون رو استخراج کنید و در سایت هایی مثل این سایت و این سایت و این سایت توکن JWT خودتون رو verify یا تست کنید و ببینید که درست تولید شده یا خیر.@RequiresApi(Build.VERSION_CODES.O)
fun convertECPublicKeyToPEM(ecPublicKey: ECPublicKey): String {
    val base64Encoded = Base64.getEncoder().encodeToString(ecPublicKey.encoded)
    return buildString {
        append(&amp;quot-----BEGIN PUBLIC KEY-----\n&amp;quot)
        append(base64Encoded.chunked(64).joinToString(&amp;quot\n&amp;quot))
        append(&amp;quot\n-----END PUBLIC KEY-----\n&amp;quot)
    }
}یه راه دومی هم برای وریفای هست که من براش یه فانکشن نوشتم که اگر خواستید میتونید ازش استفاده کنید:@RequiresApi(Build.VERSION_CODES.O)
fun manualVerifyJWT(publicKey: ECPublicKey, jwt: String): Boolean {
    val parts = jwt.split(&amp;quot.&amp;quot)
    if (parts.size != 3) return false
    val signature = Signature.getInstance(&amp;quotSHA256withECDSA&amp;quot)
    signature.initVerify(publicKey)
    signature.update(&amp;quot${parts[0]}.${parts[1]}&amp;quot.toByteArray())
    return signature.verify(Base64.getUrlDecoder().decode(parts[2]))
}یه اسکرین شات از خروجی اپ اندروید موجود در گیت هاب براتون میزارم که ببینید:در نهایت بازم از اینکه این مقاله رو مطالعه و استفاده میکنید تشکر میکنم. امیدوارم که به درک عمیق تر شما از نحوه تولید JWT کمک کرده باشه و بتونید از کدهاش استفاده کنید و نیازی به کتابخانه نداشته باشید. منتظر نظرات شما هستم که قطعا باعث رشد و پیشرفت من خواهد شد.</description>
                <category>حسین خیراله پور</category>
                <author>حسین خیراله پور</author>
                <pubDate>Thu, 28 Dec 2023 14:25:06 +0330</pubDate>
            </item>
                    <item>
                <title>پیاده سازی رمزنگاری امن مقاوم در برابر حملات در اپ های مالی اندروید</title>
                <link>https://virgool.io/@h_kheirollahpour/%D9%BE%DB%8C%D8%A7%D8%AF%D9%87-%D8%B3%D8%A7%D8%B2%DB%8C-%D8%B1%D9%85%D8%B2%D9%86%DA%AF%D8%A7%D8%B1%DB%8C-%D8%A7%D9%85%D9%86-%D8%AF%D8%B1-%D8%A7%D9%BE-%D9%87%D8%A7%DB%8C-%D9%85%D8%A7%D9%84%DB%8C-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF-e5ihfthmgdf0</link>
                <description>سلام سلام ..باتوجه به اینکه از مقاله های قبلی استقبال خوبی شد؛ تصمیم گرفتم یه مقاله جدید که مکمل خیلی خوبی برای این مقاله هست رو با یه پیاده سازی کامل تر از یه رمزنگاری امن و چفت شده با بایومتریک که در مقابل حملات هکرها مقاوم هست رو برای شما بنویسم(لینک سورس کد در گیت هاب).خب بریم سراغ اصل موضوع :)هدف اصلی این مقاله اینه که ما رمزنگاری رو با بیشترین حد ممکن که در مقابل حملات Frida مقاوم باشه رو انجام بدیم.فریدا Frida چیست؟ فریدا یک ابزار سازگار با کد پویا است که به مهندسان معکوس اجازه می‌دهد تا پارچه‌هایی از جاوااسکریپت یا کتابخانه را به برنامه‌های نیتیو بر روی iOS و Android تزریق کنند و یک فرآیند در حال اجرا را دیباگ کنند. به عبارت دیگر، به شما اجازه می‌دهد تا کد جاوااسکریپت سفارشی خود را تزریق کرده و به صورت برنامه‌ای و تعاملی فرآیندهای در حال اجرا را بررسی و تغییر دهید. زیرا فریدا ابزاری برای ابزاردهی پویا استفاده می‌کند، احتیاجی به دسترسی به کد منبع برنامه ندارد. علاوه بر این، اگر دستگاه شما دسترسی روت یا Jailbreak ندارد، نگران نباشید، فریدا همچنین بر روی دستگاه‌های عادی نیز کار می‌کند.حمله دور زدن احراز هویت(لینک توضیحات حمله)یکی از حملاتی که با فریدا انجام میدن &quot;حمله دور زدن احراز هویت بیومتریک&quot;  هست. بطور خیلی خلاصه بهتون بگم که این حمله با یه کد جاوا اسکریپت(لینک سورس کد حمله در گیت هاب) باعث صدا زده شدن متد onAuthenticationSucceeded در BiometricPrompt میشود. حالا اگر شما اگر موقع باز کردن بایومتریک آبجکت BiometricPrompt.CryptoObject(cipher) رو به اون پاس ندید و حین رمزنگاری و رمزگشایی از cipher موجود در BiometricPrompt.AuthenticationResult استفاده نکنید یه کیس خیلی خوبی برای این حمله هستید.بریم سراغ یه پیاده سازی خفن که بصورت کامل همه چیز به هم دیگه چفت شده و قابل دور زدن با این حملات نباشه :)ساختن کلید با ویژگی های امن۱.  الگوریتم انتخابی ما AES هست که جزو الگوریتم های پیچیده و امن توی دنیای آی تی شناخته میشه. بعلاوه اینکه این کلید رو با استفاده از AndroidKeyStore میسازیم. همونطور که میدونید KeyStore یه بخش محافظت شده ای هست که دسترسی به کلید تولید شده رو خیلی سخت میکنه:KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES,  &amp;quotAndroidKeyStore&amp;quot)۲. برای این کلید یه اسم انتخاب میکنیم. بعلاوه اینکه هدف مون از ایجاد کلید که رمزنگاری و رمزگشایی هست رو بهش ست میکنیم:KeyGenParameterSpec.Builder(
    val cipher = Cipher.getInstance(&amp;quotAES/GCM/NoPadding&amp;quot)
val secretKey = keyStoreManager.getKeyWithAlias(&amp;quotsample_symmetric_key_alias&amp;quot)
cipher.init(Cipher.ENCRYPT_MODE, secretKey), 
    KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
)۳. سایز این کلید بعلاوه بلاک مود و همچنین نوع پدینگ رمزنگاری رو ست میکنیم:setKeySize(256)
setBlockModes(KeyProperties.BLOCK_MODE_GCM)
setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)۴. این کلید فقط از طریق بایومتریک قابل دسترس باشه ولذا وقتی بخواییم رمزنگاری یا رمزگشایی کنیم کاربر باید فینگرپرینت فعال داشته باشه و از طریق دیالوگ prompt فینگرپرینت سیستم عامل مطمن بشیم که یوزر صاحب دیوایس هست:setUserAuthenticationRequired(true)۵. در هربار تولید متن رمزشده یک متن رمزشده رندوم تولید بشه تا از حملات ممکنه جلوگیری کنه:setRandomizedEncryptionRequired(true)۶. اگر فینگرپرینت جدیدی توی دیوایس اضافه شد این کلید ما نامعتبر بشه:if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.N) {
    setInvalidatedByBiometricEnrollment(true)
}۷. موقع رمزگشایی حتما قفل صفحه باز باشه و اگر دیوایس از StrongBox پشتیبانی میکنه حتما فرآیند تولید کلید داخل اون انجام بشه(دو فضای ایجاد کلید TEE, StrongBox داریم)val hasStrongBox = context.packageManager.hasSystemFeature(PackageManager.FEATURE_STRONGBOX_KEYSTORE)
if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.P) {
    setUnlockedDeviceRequired(true)
    if(hasStrongBox) setIsStrongBoxBacked(true)
}الف): رمزنگاری امن چفت شده با بایومتریکابتدا باید یه cipher اولیه با استفاده از کلیدی که تو مرحله قبلی ایجاد کردیم رو مقداردهی اولیه بکنیم:val encryptCipher: Cipher = Cipher.getInstance(&amp;quotAES/GCM/NoPadding&amp;quot)
val secretKey: SecretKey = keyStoreManager.getKeyWithAlias(&amp;quotsample_symmetric_key_alias&amp;quot)
encryptCipher.init(Cipher.ENCRYPT_MODE, secretKey)بعدش باید با استفاده از این cipher ی که init شده یه آبجکت کریپتو بسازیم و به BiometricPrompt پاس بدیم:val prompt = BiometricPrompt&#40;activity, ContextCompat.getMainExecutor(activity&#41;, AuthenticationCallback(out))
val info = PromptInfo.Builder()
    .setTitle(&amp;quottitle&amp;quot)
    .setNegativeButtonText(&amp;quotdescription&amp;quot)
    .setAllowedAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG)
    .build()
val crypto = BiometricPrompt.CryptoObject(encryptCipher)
prompt.authenticate(info, crypto)حالا بعد از بالا اومدن بایومتریک باید تو onAuthenticationSucceeded از آبجکت CryptoObject مقدار cipher رو استفاده کنیم:override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
    super.onAuthenticationSucceeded(result)
    val newEncryptCipher = result.cryptoObject?.cipher
    ...
}از cipher مرحله قبل برای بخش رمزنگاری استفاده میکنیم:val initializationVector = newEncryptCipher?.iv // we must save it
val plainText = ... // user input text
val cipheredBytes = newEncryptCipher?.doFinal(plaintext.toByteArray(StandardCharsets.UTF_8))
val base64EncryptedText = Base64.getEncoder().encode(cipheredBytes)در این مرحله رمزنگاری ما به اتمام میرسه و میتونیم مقدار رمزشده رو بصورت base64 encode شده یا hex encode شده ذخیره سازی کنیم.نکته: مقدار initialization vector یا iv تو این مرحله رو باید ذخیره کنیم(داخل سورس کد من با یه روشی ذخیره کردم که میتونید ازش استفاده کنید).ب): رمزگشایی امن چفت شده با بایومتریکتوی این بخش هم باید ابتدا یه cipher اولیه با استفاده از کلیدی که تو مرحله قبلی ایجاد کردیم و همچنین مقدار initialization vector ذخیره شده؛ مقداردهی اولیه بکنیم:val decryptCipher = Cipher.getInstance(&amp;quotAES/GCM/NoPadding&amp;quot)
val secretKey = keyStoreManager.getKeyWithAlias(&amp;quotsample_symmetric_key_alias&amp;quot)
decryptCipher.init(Cipher.DECRYPT_MODE, secretKey, GCMParameterSpec(128, initializationVector))بعدش باید با استفاده از این cipher ی که init شده یه آبجکت کریپتو بسازیم و به BiometricPrompt پاس بدیم:val prompt = BiometricPrompt&#40;activity, ContextCompat.getMainExecutor(activity&#41;, AuthenticationCallback(out))
val info = PromptInfo.Builder()
    .setTitle(&amp;quottitle&amp;quot)
    .setNegativeButtonText(&amp;quotdescription&amp;quot)
    .setAllowedAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG)
    .build()
val crypto = BiometricPrompt.CryptoObject(decryptCiphr)
prompt.authenticate(info, crypto)حالا بعد از بالا اومدن بایومتریک باید تو onAuthenticationSucceeded از آبجکت CryptoObject مقدار cipher رو استفاده کنیم:override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
    super.onAuthenticationSucceeded(result)
    val newDecryptCipher = result.cryptoObject?.cipher
    ...
}بعد از دیکد کردن متن رمزشده ذخیره شده در مرحله رمزنگاری و همچنین استفاده از cipher مرحله قبل؛ رمزگشایی رو انجام میدیم:val encryptedBytes = Base64.getDecoder().decode(base64EncryptedText)
val text = newDecryptCipher?.doFinal(encryptedBytes)
val plaintext = String(text, StandardCharsets.UTF_8)توی این مرحله هم رمزگشایی ما به پایان میرسه و میتونیم از متن حاصل شده تو جاهای مختلف استفاده کنیم.در پایان ما یاد گرفتیم که چطور یک کلید متقارن و امن با کلی ویژگی های امنیتی در اندروید تولید کنیم و بعد از اون نحوه رمزنگاری و رمزگشایی با استفاده از اون کلید که کاملا چفت شده با بایومتریک و مقاوم در مقابل حملات فریدا باشه رو یاد گرفتیم. منتظر نظرات سازنده شما هستم ..</description>
                <category>حسین خیراله پور</category>
                <author>حسین خیراله پور</author>
                <pubDate>Thu, 30 Nov 2023 15:52:56 +0330</pubDate>
            </item>
                    <item>
                <title>۳. پیاده سازی الگوریتم های برگشت ناپذیر یا HASH در اندروید</title>
                <link>https://virgool.io/@h_kheirollahpour/%DB%B3-%D9%BE%DB%8C%D8%A7%D8%AF%D9%87-%D8%B3%D8%A7%D8%B2%DB%8C-%D8%A7%D9%84%DA%AF%D9%88%D8%B1%DB%8C%D8%AA%D9%85-%D9%87%D8%A7%DB%8C-%D8%A8%D8%B1%DA%AF%D8%B4%D8%AA-%D9%86%D8%A7%D9%BE%D8%B0%DB%8C%D8%B1-%DB%8C%D8%A7-hash-%D8%AF%D8%B1-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF-w1p2vwycgf4m</link>
                <description>در این نوع الگوریتم ها کلیدی ایجاد نمیشه بلکه یک متن ورودی از کاربر گرفته میشه و در نهایت با توجه به سایز مورد نظر؛ یک متن یکتا و اصطلاحا یونیک ساخته میشه که دیگه نمیشه از متن تولید شده به متن اولیه رسید و لذا کاملا یکطرفه و غیر قابل بازگشت هست. پرکاربرد ترین استفاده از این الگوریتم هم ذخیره سازی پسورد هش شده کاربرها در سمت سرور یا کلاینت هست(لینک گیت هاب پروژه و لینک مقاله اصلی).بریم سراغ پیاده سازی ... ما از الگوریتم SHA برای تولید متن هش استفاده میکنیم. سایز مد نظر ما ۲۵۶ هست که در نهایت extension function زیر کار تولید متن هش رو برای ما انجام میده:fun String.sha256(): ByteArray {
    val digest = MessageDigest.getInstance(&amp;quotSHA-256&amp;quot)
    return digest.digest(this.toByteArray())
}حالا این متن هش شده به چه کاری میاد؟ سوال خوبیه .. بیایید یه مثال کاربردی بزنیم ..فرض کنید که شما در کلاینت از کاربر پسورد رو میگیرید و اون رو میخوایید ذخیره کنید. حالا اگر متن خام رو ذخیره کنید که یک لقمه چرب و نرم برای هکرها هستید. چاره چیه ؟ ما میتونیم پسورد هش شده رو سمت کلاینت ذخیره کنیم. حالا وقتی کاربر پسورد خام رو وارد میکنه ما میتونیم اون رو هش کنیم و با متن هش ذخیره شده مقایسه کنیم و به این صورت از درست بودن پسورد وارد شده از سمت کاربر مطمن بشیم. البته این نکته رو یاداوری کنم که ذخیره پسورد هش شده سمت سرور روش مرسومی هست.حالا طبق صحبت های بالا کد زیر رو برای چک کردن متن پسورد وارد شده توسط کاربر میتونید استفاده کنید:fun verifyHashedMessage(plainData: String, hashedData: ByteArray): Boolean {
    return hashedData.contentEquals(plainData.sha256())
}در این مقاله هم سعی کردم که بحث الگوریتم های رمزنگاری غیر قابل بازگشت رو هم بصورت کاربردی و همراه با کد برای شما عزیزان توضیح بدم. امیدوارم که براتون مفید بوده باشه. منتظر نظرات و فیدبک های شما هستم.</description>
                <category>حسین خیراله پور</category>
                <author>حسین خیراله پور</author>
                <pubDate>Fri, 17 Nov 2023 15:04:53 +0330</pubDate>
            </item>
                    <item>
                <title>۲. پیاده سازی الگوریتم های نامتقارن یا Asymmetric در اندروید با استفاده از AndroidKeyStore</title>
                <link>https://virgool.io/@h_kheirollahpour/2-%D9%BE%DB%8C%D8%A7%D8%AF%D9%87-%D8%B3%D8%A7%D8%B2%DB%8C-%D8%A7%D9%84%DA%AF%D9%88%D8%B1%DB%8C%D8%AA%D9%85-%D9%87%D8%A7%DB%8C-%D9%86%D8%A7%D9%85%D8%AA%D9%82%D8%A7%D8%B1%D9%86-%DB%8C%D8%A7-asymmetric-%D8%AF%D8%B1-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF-%D8%A8%D8%A7-%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-androidkeystore-n7mw6bhugrkh</link>
                <description>در این نوع الگوریتم ها دو کلید ایجاد میشه و کلیدهای رمزنگاری و رمزگشایی متفاوت هستن. مثل الگوریتم های متقارن ما بازم سعی میکنیم که امنیت کلید رو به بیشترین حد ممکن ایجاد کنیم(لینک گیت هاب پروژه و لینک مقاله اصلی).بریم سراغ پیاده سازی ..۱. الگوریتم نامتقارن انتخابی ما EC هست که این مورد هم جزو الگوریتم های معروف و شناخته شده هست. ما این کلید رو هم با استفاده از AndroidKeyStore میسازیم:KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_EC,  &amp;quotAndroidKeyStore&amp;quot)۲. یک اسم برای این کلید انتخاب میکنیم. بعلاوه اینکه هدف مون از ایجاد کلید که ساین و وریفای هست رو بهش ست میکنیم:KeyGenParameterSpec.Builder(
    &amp;quotsample_asymmetric_key_alias&amp;quot,
    KeyProperties.PURPOSE_SIGN or KeyProperties.PURPOSE_VERIFY
)۳. طول کلید و همچنین نوع دایجست رو ست میکنیم:setKeySize(256)
setDigests(KeyProperties.DIGEST_SHA256)۴. پارامتری ست میکنیم که این کلید فقط از طریق بایومتریک قابل دسترس باشه ولذا وقتی بخواییم ساین و وریفای کنیم کاربر باید فینگرپرینت فعال داشته باشه و از طریق دیالوگ prompt فینگرپرینت سیستم عامل مطمن بشیم که یوزر صاحب دیوایس هست:setUserAuthenticationRequired(true)۵. در هربار تولید سیگنیچر یک متن رمزشده رندوم تولید بشه تا از حملات ممکنه جلوگیری کنه:setRandomizedEncryptionRequired(true)۶. نوع دقیق مشخصه استاندارد الگوریتم تولید کلید EC رو ست میکنیم:setAlgorithmParameterSpec(ECGenParameterSpec(&amp;quotsecp256r1&amp;quot))۷. مدت زمان اعتبار کلید بعد از انجام بایومتریک صحیح:if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.R) { 
    setUserAuthenticationParameters(10, KeyProperties.AUTH_BIOMETRIC_STRONG) 
} else { 
    setUserAuthenticationValidityDurationSeconds(10) 
}۸. اگر فینگرپرینت جدیدی توی دیوایس اضافه شد این کلید ما نامعتبر بشه:if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.N) {
    setInvalidatedByBiometricEnrollment(true)
}۹. موقع رمزگشایی حتما قفل صفحه باز باشه و اگر دیوایس از StrongBox پشتیبانی میکنه حتما فرآیند تولید کلید داخل اون انجام بشه(دو فضای ایجاد کلید TEE, StrongBox داریم)val hasStrongBox = context.packageManager.hasSystemFeature(PackageManager.FEATURE_STRONGBOX_KEYSTORE)
if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.P) {     
    setUnlockedDeviceRequired(true)     
    if(hasStrongBox) setIsStrongBoxBacked(true) 
}توی مرحله بعد برای ساین یا sign از کد زیر استفاده میکنیم:val plainMessage = ... // user input text
val signature = Signature.getInstance(&amp;quotSHA256withECDSA&amp;quot).run {
    initSign(getPrivateKey())
    update(plainMessage.toByteArray())
    sign()
}و همچنین برای وریفای یا verify هم از کد زیر استفاده میکنیم:val plainMessage = ... // user input text
val signature = ... // signed message of user input
val isVerified = Signature.getInstance(&amp;quotSHA256withECDSA&amp;quot).run {
    initVerify(getPublicKey())
    update(plainMessage.toByteArray())
    verify(signature.toByteArray())
} در پایان ما یاد گرفتیم که چطور یک کلید نامتقارن و امن با کلی ویژگی های امنیتی در اندروید تولید کنیم و بعد از اون نحوه ساین و وریفای با استفاده از ترکیب اون کلیدها رو هم فرا گرفتیم.</description>
                <category>حسین خیراله پور</category>
                <author>حسین خیراله پور</author>
                <pubDate>Fri, 17 Nov 2023 14:24:49 +0330</pubDate>
            </item>
                    <item>
                <title>۱. پیاده سازی الگوریتم های متقارن یا Symmetric در اندروید با استفاده از AndroidKeyStore</title>
                <link>https://virgool.io/@h_kheirollahpour/1-%D9%BE%DB%8C%D8%A7%D8%AF%D9%87-%D8%B3%D8%A7%D8%B2%DB%8C-%D8%A7%D9%84%DA%AF%D9%88%D8%B1%DB%8C%D8%AA%D9%85-%D9%87%D8%A7%DB%8C-%D9%85%D8%AA%D9%82%D8%A7%D8%B1%D9%86-%DB%8C%D8%A7-symmetric-%D8%AF%D8%B1-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF-%D8%A8%D8%A7-%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-androidkeystore-c1lkdftmwyhx</link>
                <description>تو این الگوریتم ها یک کلید واحد ساخته میشه که به وسیله اون ما سمت کلاینت اندروید رمزنگاری رو انجام میدیم و بعدا هم باید با همون کلید رمزگشایی رو هم انجام بدیم. ما سعی میکنیم که امنیت کلیدمون رو با بیشترین حد ممکن ایجاد کنیم(لینک گیت هاب پروژه و لینک مقاله اصلی).بریم سراغ پیاده سازی ..۱.  الگوریتم انتخابی ما AES هست که جزو الگوریتم های پیچیده و امن توی دنیای آی تی شناخته میشه. بعلاوه اینکه این کلید رو با استفاده از AndroidKeyStore میسازیم. همونطور که میدونید KeyStore یه بخش محافظت شده ای هست که دسترسی به کلید تولید شده رو خیلی سخت میکنه:KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES,  &amp;quotAndroidKeyStore&amp;quot)۲. برای این کلید یه اسم انتخاب میکنیم. بعلاوه اینکه هدف مون از ایجاد کلید که رمزنگاری و رمزگشایی هست رو بهش ست میکنیم:KeyGenParameterSpec.Builder(
    &amp;quotsample_symmetric_key_alias&amp;quot, 
    KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
)۳. سایز این کلید بعلاوه بلاک مود و همچنین نوع پدینگ رمزنگاری رو ست میکنیم:setKeySize(256)
setBlockModes(KeyProperties.BLOCK_MODE_GCM)
setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)۴. این کلید فقط از طریق بایومتریک قابل دسترس باشه ولذا وقتی بخواییم رمزنگاری یا رمزگشایی کنیم کاربر باید فینگرپرینت فعال داشته باشه و از طریق دیالوگ prompt فینگرپرینت سیستم عامل مطمن بشیم که یوزر صاحب دیوایس هست:setUserAuthenticationRequired(true)۵. در هربار تولید متن رمزشده یک متن رمزشده رندوم تولید بشه تا از حملات ممکنه جلوگیری کنه:setRandomizedEncryptionRequired(true)۶. مدت زمان اعتبار کلید بعد از انجام بایومتریک صحیح:if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.R) {
    setUserAuthenticationParameters(10, KeyProperties.AUTH_BIOMETRIC_STRONG)
} else {
    setUserAuthenticationValidityDurationSeconds(10)
}۷. اگر فینگرپرینت جدیدی توی دیوایس اضافه شد این کلید ما نامعتبر بشه:if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.N) {
    setInvalidatedByBiometricEnrollment(true)
}۸. موقع رمزگشایی حتما قفل صفحه باز باشه و اگر دیوایس از StrongBox پشتیبانی میکنه حتما فرآیند تولید کلید داخل اون انجام بشه(دو فضای ایجاد کلید TEE, StrongBox داریم)val hasStrongBox = context.packageManager.hasSystemFeature(PackageManager.FEATURE_STRONGBOX_KEYSTORE)
if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.P) {
    setUnlockedDeviceRequired(true)
    if(hasStrongBox) setIsStrongBoxBacked(true)
}توی مرحله بعد برای رمزنگاری یا encrypt از کد زیر استفاده میکنیم:val plainText = ... // user input text
val plainBytes = plainText.toByteArray(StandardCharsets.UTF_8)
val key = keyStoreManager.getKeyWithAlias(KEY_ALIAS_SYMMETRIC)
val cipher = Cipher.getInstance(AES_GCM_NOPADDING)
cipher.init(Cipher.ENCRYPT_MODE, key)
val initailVector = cipher.iv
val encryptedBytes = cipher.doFinal(plainBytes)و همچنین برای رمزگشایی یا decrypt هم از کد زیر استفاده میکنیم:val encryptedBytes = ... // encrypted byte array val key = keyStoreManager.getKeyWithAlias(KEY_ALIAS_SYMMETRIC) val spec = GCMParameterSpec(AUTHENTICATION_TAG_SIZE, iv) val cipher = Cipher.getInstance(AES_GCM_NOPADDING) cipher.init(Cipher.DECRYPT_MODE, key, spec) val decryptedBytes = cipher.doFinal(encryptedBytes) val plainText = String(decryptedBytes, StandardCharsets.UTF_8)در پایان ما یاد گرفتیم که چطور یک کلید متقارن و امن با کلی ویژگی های امنیتی در اندروید تولید کنیم و بعد از اون نحوه رمزنگاری و رمزگشایی با استفاده از اون کلید رو هم فرا گرفتیم.</description>
                <category>حسین خیراله پور</category>
                <author>حسین خیراله پور</author>
                <pubDate>Tue, 14 Nov 2023 14:42:12 +0330</pubDate>
            </item>
                    <item>
                <title>امنیت داده در اندروید</title>
                <link>https://virgool.io/@h_kheirollahpour/%D8%A7%D9%85%D9%86%DB%8C%D8%AA-%D8%AF%D8%A7%D8%AF%D9%87-%D8%AF%D8%B1-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF-hexjltvvmnq2</link>
                <description>سلام .. امیدوارم حالتون خوب باشه .. در این مقاله سعی میکنم به صورت خلاصه و کاربردی به موضوع امنیت داده در اندروید بپردازم. در ابتدا یه توضیح مختصری راجع به الگوریتم های رمزنگاری میدم و بعدش پیاده سازی هرکدوم از روش ها رو توی اندروید بصورت پست های جداگانه که لینک اونها تو پایین صفحه وجود داره به شما توضیح میدم. تمام پیاده سازی ها هم بصورت یک پروژه اندرویدی توی این لینک گیت هاب وجود داره که میتونید ازش استفاده کنید.روش های رمزنگاری داده:در هر نرم افزاری رمزنگاری داده از اهمیت ویژه ای برخوردار هست و نرم افزارهای اندرویدی هم از این قایده مستثنا نیستن. ولی باتوجه به نوع کاری که در اندروید انجام میشه میتونیم از روش های مختلف رمزنگاری استفاده کنیم. بصورت کلی روش های رمزنگاری به دو دسته الگوریتم های برگشت پذیر و برگشت ناپذیر تقسیم میشن. برای تولید کلید تو روش های برگشت پذیر ما میخواییم با بیشترین امنیت ممکن این روش ها رو توی اندروید پیاده سازی کنیم؛ لذا از AndroidKeyStore استفاده میکنیم. حالا بصورت خیلی ساده به توضیح این روش ها میپردازیم:الگوریتم های برگشت پذیر یا Reversible:به الگوریتم هایی گفته میشه که ما یک متن رو رمزنگاری میکنیم و در آینده اون متن رمزشده با استفاده از الگوریتم های رمزنگاری دقیقا به همون متن اولیه برمیگرده رو الگوریتم برگشت پذیر میگن. این الگوریتم ها به دو دسته متقارن و نامتقارن تقسیم میشن:الگوریتم های متقارن یا symmetric: الگوریتم هایی هستن که کلید رمزنگاری و رمزگشایی توی اونها دقیقا یکسان هست. ما توی این مقاله به نحوه پیاده سازی الگوریتم AES با استفاده از AndroidKeyStore میپردازیم.الگوریتم های نامتقارن یا asymmetric: الگوریتم هایی هستن که کلید رمزنگاری و رمزگشایی باهم تفاوت دارن. ما توی این مقاله به نحوه پیاده سازی الگوریتم EC با استفاده از AndroidKeyStore میپردازیم.الگوریتم های برگشت ناپذیر یا Irreversible:به الگوریتم هایی میگن که ما یک متن رو رمزنگاری میکنیم اما در آینده به هیچ وجه قابل برگشت به متن اولیه نیستن رو الگوریتم برگشت ناپذیر میگن. ما توی این مقاله به نحوه پیاده سازی الگوریتم SHA توی اندروید میپردازیم. خب دیگه .. بریم سراغ اصل مطلب و پیاده سازی روش های گفته شده تو بالا:1. پیاده سازی الگوریتم های متقارن یا Symmetric در اندروید با استفاده از AndroidKeyStore2. پیاده سازی الگوریتم های نامتقارن یا Asymmetric در اندروید با استفاده از AndroidKeyStore3. پیاده سازی الگوریتم های هش یا Hash در اندروید با استفاده از AndroidKeyStore</description>
                <category>حسین خیراله پور</category>
                <author>حسین خیراله پور</author>
                <pubDate>Tue, 14 Nov 2023 14:06:10 +0330</pubDate>
            </item>
            </channel>
</rss>