নোড.জেএস হ্যাশ স্ট্রিং?


325

আমার একটি স্ট্রিং রয়েছে যা আমি হ্যাশ করতে চাই। নোড.জেএসে হ্যাশ তৈরির সহজতম উপায় কী?

হ্যাশটি সুরক্ষার জন্য নয়, সংস্করণকরণের জন্য।


উত্তর:


224

কটাক্ষপাত crypto.createHash (এলগরিদম)

var filename = process.argv[2];
var crypto = require('crypto');
var fs = require('fs');

var md5sum = crypto.createHash('md5');

var s = fs.ReadStream(filename);
s.on('data', function(d) {
  md5sum.update(d);
});

s.on('end', function() {
  var d = md5sum.digest('hex');
  console.log(d + '  ' + filename);
});

S.on () ফাংশনটি কী করছে? এটি প্রতিবার স্ট্রিম থেকে ডেটা পড়ার সময় কার্যকর করার জন্য md5sum.update (d) ফাংশনটি নিবন্ধভুক্ত করছে?
DucRP

@ YoniDor আপনি fs.readsync চেষ্টা করেছেন ? - পরিপাকের একটি ক্লাসিক যখন-লুপ, তারপর নিশ্চিত যে এটা সম্পন্ন হতে ... ➝ stackoverflow.com/a/21219407/444255
ফ্রাঙ্ক Nocke

8
ওপি একটি ফাইল নয়, একটি স্ট্রিং হ্যাশ করতে চায়।
blompse

697

আপনি যদি এমডি 5 হ্যাশ করতে চান তবে একটি সরল স্ট্রিং আমি পেয়েছি এটি আমার জন্য কাজ করে।

var crypto = require('crypto');
var name = 'braitsch';
var hash = crypto.createHash('md5').update(name).digest('hex');
console.log(hash); // 9b74c9897bac770ffc029102a200c5de

181
ওয়াট ওয়াট, আপনি যদি require('crypto').createHash('md5').update(STRING_TO_BE_HASHED).digest("hex")ওয়ান-লাইনার পান। চিয়ারস সাথী!
বালুপটন

3
ওয়ান-লাইনার ব্যবহার করে সমাধানটি ব্যবহার করার চেষ্টা করার সময় .updateএকাধিকবার ( github.com/joyent/node/issues/749 ) ব্যবহার করে কিছু সমস্যা ছিল timbooo(কারণ হ্যাশ বস্তুটি প্রতিবার পুনরায় তৈরি করা হয়েছে)।
সর্বোচ্চ

স্ট্রিংয়ের দৈর্ঘ্য পরিবর্তন করার কোনও উপায়? কেবল 32 টি অক্ষর নয়, 64 বা 128 বা একটি ভিন্ন সংখ্যা।
মাইকেল 11

@ মাইকেল চেষ্টা করুন যদি আপনার প্রয়োজন অনুসারে অন্যান্য হ্যাশ অ্যালগরিদম থাকে তবে এমডি 5 সর্বদা 32 টি অক্ষর।
টাইম

আমার যদি হ্যাশের প্রচুর স্ট্রিং থাকে তবে ফলটি পুনরায় ব্যবহারের পরিবর্তে ক্রিপ্টো.ক্রেটহ্যাশকে কল করা কম দক্ষ?
মাইকেল

81

নোডের ক্রিপ্টো মডিউল API এখনও অস্থির।

সংস্করণ ৪.০ হিসাবে, নেটিভ ক্রিপ্টো মডিউলটি আর অস্থির নয়। থেকে সরকারী ডকুমেন্টেশন :

ক্রিপ্টো

স্থায়িত্ব: 2 - স্থিতিশীল

এপিআই সন্তোষজনক প্রমাণিত হয়েছে। এনপিএম ইকোসিস্টেমের সাথে সামঞ্জস্যতা একটি উচ্চ অগ্রাধিকার, এবং একেবারে প্রয়োজনীয় না হলে ভাঙা হবে না।

সুতরাং, বাহ্যিক নির্ভরতা ছাড়াই দেশীয় বাস্তবায়ন ব্যবহার করা নিরাপদ হিসাবে বিবেচনা করা উচিত।

রেফারেন্সের জন্য, বেলো উল্লিখিত মডিউলগুলি বিকল্প সমাধান হিসাবে প্রস্তাবিত হয়েছিল যখন ক্রিপ্টো মডিউলটি এখনও অস্থির ছিল।


আপনি মডিউলগুলি শ 1 বা এমডি 5 ব্যবহার করতে পারেন যা উভয়ই কাজ করে।

$ npm install sha1

এবং তারপর

var sha1 = require('sha1');

var hash = sha1("my message");

console.log(hash); // 104ab42f1193c336aa2cf08a2c946d5c6fd0fcdb

অথবা

$ npm install md5

এবং তারপর

var md5 = require('md5');

var hash = md5("my message");

console.log(hash); // 8ba6c19dc1def5702ff5acbf2aeea5aa

(এমডি 5 নিরাপত্তাহীন তবে প্রায়শই গ্রাভাটারের মতো পরিষেবা ব্যবহার করে)

এই মডিউলগুলির API পরিবর্তন হবে না!


9
আমি মনে করি সম্পূর্ণ নতুন মডিউল আনার চেয়ে ক্রিপ্টোকে ব্যবহার করা অনেক সহজ এবং দক্ষ।
ভালজাস

6
বর্তমান নোড.জেএস ডক্স থেকে: "স্থায়িত্ব: 2 - অস্থির; এপিআই পরিবর্তনগুলি ভবিষ্যতের সংস্করণগুলির জন্য আলোচনা করা হচ্ছে Bre ব্রেকিং পরিবর্তনগুলি হ্রাস করা হবে will" আমার মডিউলটির API পরিবর্তন হবে না। আমি যখন প্রথমদিকে মডিউলটি লিখেছিলাম তখন প্ল্যাটফর্মটিতে কোনও crypto মডিউল নির্মিত হয়নি । আরেকটি সুবিধা হ'ল আপনি আমার মডিউলটি সার্ভারে পাশাপাশি ক্লায়েন্ট সাইডটি ব্যবহার করতে পারেন। তবে আপনি কোন লাইব্রেরি ব্যবহার করেন এটি সম্পূর্ণ আপনার উপর নির্ভর করে।
pvorb

7
ক্রিপ্টো হ্যাশগুলিতে বিল্ডটি আমাকে 'হ্যাশ আপডেট ব্যর্থ' বিএস দিয়ে চলেছে। অবশেষে আমি MD5 মডিউলে চলে এসেছি এবং এটি ঠিক কাজ করেছে। কল করাও সহজ (কিছুটা)। ধন্যবাদ.
জিজেকে

2
(2) থেকে দূরে থাকা কোনও বিকল্পের জন্য +1 - ক্রিপ্টো এপিআইয়ের অস্থির প্রকৃতি!
গীক স্টক

1
আমি এই মডিউলটির জন্য স্ট্যান্ডার্ড ক্রিপ্টো ব্যবহারের জন্য অদলবদল করে আমার উইন্ডোজ মেশিনে নোড 0.11.x এ একটি অদ্ভুত sha1 সমস্যা সমাধান করেছি।
বার্টভিডস

24
sha256("string or binary");

আমি অন্যান্য উত্তর সঙ্গে সমস্যা অভিজ্ঞ। আমি আপনাকে binaryবাইট স্ট্রিংটি ব্যবহার করার জন্য জাভাস্ক্রিপ্ট (নোডজেএস) এবং পাইথন, পিএইচপি, গিথুবের মতো অন্যান্য ল্যাঙ্গেজ / পরিষেবার মধ্যে বিভিন্ন হ্যাশ প্রতিরোধ করার জন্য এনকোডিং যুক্তি সেট করার পরামর্শ দিচ্ছি ...

আপনি যদি এই কোডটি ব্যবহার না করেন তবে আপনি নোডজেএস এবং পাইথনের মধ্যে একটি আলাদা হ্যাশ পেতে পারেন ...

পাইথন, পিএইচপি, পার্ল, গিথুব (এবং কোনও সমস্যা রোধ করে) একই হ্যাশ কীভাবে পাবেন:

নোডজেএসটি স্ট্রিংয়ের ইউটিএফ -8 উপস্থাপনা নিয়ে যাচ্ছে। অন্যান্য ভাষা (যেমন পাইথন, পিএইচপি বা পিইআরএল ...) বাইট স্ট্রিংটি হ্যাশ করছে।

বাইট স্ট্রিংটি ব্যবহার করতে আমরা বাইনারি যুক্তি যুক্ত করতে পারি ।

কোড:

const crypto = require("crypto");

function sha256(data) {
    return crypto.createHash("sha256").update(data, "binary").digest("base64");
    //                                               ------  binary: hash the byte string
}

sha256("string or binary");

ডকুমেন্টেশন:

  • crypto.createHash (অ্যালগোরিদম [, অপশন]]: অ্যালগরিদম প্ল্যাটফর্মে ওপেনএসএসএল সংস্করণ দ্বারা সমর্থিত উপলভ্য অ্যালগরিদমগুলির উপর নির্ভরশীল।
  • হ্যাশ.ডিজাস্ট ([এনকোডিং]): এনকোডিংটি 'হেক্স', 'ল্যাটিন 1' বা 'বেস 64' হতে পারে। (বেস 64 কম দীর্ঘ)

আপনি সমস্যাটি পেতে পারেন: sha256 ("\ xac"), "\ xd1", "\ xb9", "\ xe2", "\ xbb", "\ x93", ইত্যাদি ...

  • অন্যান্য ভাষা (যেমন পিএইচপি, পাইথন, পার্ল ...) এবং এর সাথে আমার সমাধান .update(data, "binary"):

    sha1("\xac") //39527c59247a39d18ad48b9947ea738396a3bc47
  • ডিফল্টভাবে নোডেজ (বাইনারি ছাড়াই):

    sha1("\xac") //f50eb35d94f1d75480496e54f4b4a472a9148752

15

cryptoমডিউল এই খুব সহজ করে তোলে।

সেটআপ:

// import crypto from 'crypto';
const crypto = require('crypto');

const sha256 = x => crypto.createHash('sha256').update(x, 'utf8').digest('hex');

ব্যবহার:

sha256('Hello, world. ');

10

এখানে আপনি আপনার হার্ডওয়্যারে সমস্ত সমর্থিত হ্যাশগুলিকে আপনার নোড.জেএস এর সংস্করণ দ্বারা সমর্থিত বেঞ্চমার্ক করতে পারেন Here কিছু ক্রিপ্টোগ্রাফিক এবং কিছু কিছু কেবল একটি চেকসামের জন্য। প্রতিটি অ্যালগরিদমের জন্য এটি "হ্যালো ওয়ার্ল্ড" গণনা করে 1 মিলিয়ন বার। প্রতিটি অ্যালগরিদমের জন্য এটি প্রায় 1-15 সেকেন্ড সময় নিতে পারে (নোড.জেএস 4.2.2 সহ স্ট্যান্ডার্ড গুগল কম্পিউটিং ইঞ্জিনে পরীক্ষিত)।

for(var i1=0;i1<crypto.getHashes().length;i1++){
  var Algh=crypto.getHashes()[i1];
  console.time(Algh);
  for(var i2=0;i2<1000000;i2++){
    crypto.createHash(Algh).update("Hello World").digest("hex");
  }
  console.timeEnd(Algh);  
}

ফলাফল:
জেলাকে: 1992ms
জেলাকে Sha,: 1960ms
জেলাকে-SHA1 এ: 2062ms
জেলাকে-SHA1 এ বয়সী: 2124ms
, RSA-MD4: 1893ms
, RSA-MD5: 1982ms
, RSA-MDC2: 2797ms
, RSA-RIPEMD160: 2101ms
আরএসএ Sha,: 1948ms
, RSA-SHA1 এ : 1908ms
, RSA-SHA1-2: 2042ms
, RSA-SHA224: 2176ms
, RSA-ভিন্ন ধরনের SHA256: 2158ms
, RSA-SHA384: 2290ms
, RSA-SHA512: 2357ms
dsaEncryption: 1936ms
dsaWithSHA: 1910ms
dsaWithSHA1: 1926ms
dss1: 1928ms
ECDSA-সঙ্গে-SHA1 এ: 1880ms
MD4: 1833ms
এমডি 4 উইথআরএসএ এনক্রিপশন: 1925 মিমি এমডি 5: 1863ms
এমডি 5
উইথআরএসএএনক্রিপশন: 1923ms
এমডিসি 2: 2729
মিমি এমডিসি 2 উইথআরএসএ: 2890 মিমি
ripemd: 2101ms
ripemd160: 2153ms
ripemd160WithRSA: 2210ms
rmd160: 2146ms
Sha: 1929ms
SHA1: 1880ms
sha1WithRSAEncryption: 1957ms
SHA224: 2121ms
sha224WithRSAEncryption: 2290ms
SHA256: 2134ms
sha256WithRSAEncryption: 2190ms
SHA384: 2181ms
sha384WithRSAEncryption: 2343ms
SHA512: 2371ms
sha512WithRSAEncryption: 2434ms
shaWithRSAEncryption: 1966ms
ssl2- md5: 1853ms
ssl3-md5: 1868ms
ssl3-sha1: 1971ms
ঘূর্ণি: 2578ms


1
আমাদের কি করতে RSA-উপসর্গ কি?
বালুপটন

7

সরল ওয়ান লাইনার:

আপনি যদি ইউটিএফ 8 পাঠ্য হ্যাশ চান:

const hash = require('crypto').createHash('sha256').update('Hash me', 'utf8').digest('hex');

আপনি যদি পাইথন, পিএইচপি, পার্ল, গিথুব সহ ​​একই হ্যাশ পেতে চান:

const hash = require('crypto').createHash('sha256').update('Hash me', 'binary').digest('hex');

এছাড়াও আপনি প্রতিস্থাপন করতে পারেন 'sha256'সঙ্গে 'sha1', 'md5', 'sha256','sha512'


1

Http://www.thoughtcrime.org/blog/the-cryptographic-doom-pr صولle / থেকে ধারণাগুলি বিবেচনা করে (সংক্ষেপে: প্রথম এনক্রিপ্ট করুন, তারপরে প্রমাণীকরণ করুন FIR JS:

function encrypt(text,password){
  var cipher = crypto.createCipher(algorithm,password)
  var crypted = cipher.update(text,'utf8','hex')
  crypted += cipher.final('hex');
  return crypted;
}

function decrypt(text,password){
  var decipher = crypto.createDecipher(algorithm,password)
  var dec = decipher.update(text,'hex','utf8')
  dec += decipher.final('utf8');
  return dec;
}

function hashText(text){
    var hash = crypto.createHash('md5').update(text).digest("hex");
    //console.log(hash); 
    return hash;
}

function encryptThenAuthenticate(plainText,pw)
{
    var encryptedText = encrypt(plainText,pw);
    var hash = hashText(encryptedText);
    return encryptedText+"$"+hash;
}
function VerifyThenDecrypt(encryptedAndAuthenticatedText,pw)
{
    var encryptedAndHashArray = encryptedAndAuthenticatedText.split("$");
    var encrypted = encryptedAndHashArray[0];
    var hash = encryptedAndHashArray[1];
    var hash2Compare = hashText(encrypted);
    if (hash === hash2Compare)
    {
        return decrypt(encrypted,pw); 
    }
}

এটি দিয়ে পরীক্ষা করা যেতে পারে:

var doom = encryptThenAuthenticate("The encrypted text",user.cryptoPassword);
console.log(VerifyThenDecrypt(doom,user.cryptoPassword));

আশাকরি এটা সাহায্য করবে :-)


1

আমি নীলিমিপ-এমডি 5 ব্যবহার করি যা "নোড.জেএস এর মতো সার্ভার-পার্শ্বের পরিবেশের সাথে সামঞ্জস্যপূর্ণ, মডিউল লোডারগুলির মতো প্রয়োজনীয় জেএস, ব্রাউজারফি বা ওয়েবপ্যাক এবং সমস্ত ওয়েব ব্রাউজারগুলি রয়েছে।"

এটি এর মতো ব্যবহার করুন:

var md5 = require("blueimp-md5");

var myHashedString = createHash('GreensterRox');

createHash(myString){
    return md5(myString);
}

যদি খোলা জায়গায় হ্যাশ মানগুলি পাস করা হয় তবে তাদের নুন দেওয়া সর্বদা ভাল ধারণা যাতে লোকেরা তাদের পুনরায় তৈরি করা কঠিন:

createHash(myString){
    var salt = 'HnasBzbxH9';
    return md5(myString+salt);
}

1
function md5(a) {
    var r = 0,
        c = "";
    return h(a);

    function h(t) {
        return u(l(m(t)))
    }

    function l(t) {
        return p(g(f(t), 8 * t.length))
    }

    function u(t) {
        for (var e, i = r ? "0123456789ABCDEF" : "0123456789abcdef", n = "", o = 0; o < t.length; o++)
            e = t.charCodeAt(o),
            n += i.charAt(e >>> 4 & 15) + i.charAt(15 & e);
        return n
    }

    function m(t) {
        for (var e, i, n = "", o = -1; ++o < t.length;)
            e = t.charCodeAt(o),
            i = o + 1 < t.length ? t.charCodeAt(o + 1) : 0,
            55296 <= e && e <= 56319 && 56320 <= i && i <= 57343 && (e = 65536 + ((1023 & e) << 10) + (1023 & i),
                o++),
            e <= 127 ? n += String.fromCharCode(e) : e <= 2047 ? n += String.fromCharCode(192 | e >>> 6 & 31, 128 | 63 & e) : e <= 65535 ? n += String.fromCharCode(224 | e >>> 12 & 15, 128 | e >>> 6 & 63, 128 | 63 & e) : e <= 2097151 && (n += String.fromCharCode(240 | e >>> 18 & 7, 128 | e >>> 12 & 63, 128 | e >>> 6 & 63, 128 | 63 & e));
        return n
    }

    function f(t) {
        for (var e = Array(t.length >> 2), i = 0; i < e.length; i++)
            e[i] = 0;
        for (i = 0; i < 8 * t.length; i += 8)
            e[i >> 5] |= (255 & t.charCodeAt(i / 8)) << i % 32;
        return e
    }

    function p(t) {
        for (var e = "", i = 0; i < 32 * t.length; i += 8)
            e += String.fromCharCode(t[i >> 5] >>> i % 32 & 255);
        return e
    }

    function g(t, e) {
        t[e >> 5] |= 128 << e % 32,
            t[14 + (e + 64 >>> 9 << 4)] = e;
        for (var i = 1732584193, n = -271733879, o = -1732584194, s = 271733878, a = 0; a < t.length; a += 16) {
            var r = i,
                c = n,
                h = o,
                l = s;
            n = E(n = E(n = E(n = E(n = N(n = N(n = N(n = N(n = C(n = C(n = C(n = C(n = S(n = S(n = S(n = S(n, o = S(o, s = S(s, i = S(i, n, o, s, t[a + 0], 7, -680876936), n, o, t[a + 1], 12, -389564586), i, n, t[a + 2], 17, 606105819), s, i, t[a + 3], 22, -1044525330), o = S(o, s = S(s, i = S(i, n, o, s, t[a + 4], 7, -176418897), n, o, t[a + 5], 12, 1200080426), i, n, t[a + 6], 17, -1473231341), s, i, t[a + 7], 22, -45705983), o = S(o, s = S(s, i = S(i, n, o, s, t[a + 8], 7, 1770035416), n, o, t[a + 9], 12, -1958414417), i, n, t[a + 10], 17, -42063), s, i, t[a + 11], 22, -1990404162), o = S(o, s = S(s, i = S(i, n, o, s, t[a + 12], 7, 1804603682), n, o, t[a + 13], 12, -40341101), i, n, t[a + 14], 17, -1502002290), s, i, t[a + 15], 22, 1236535329), o = C(o, s = C(s, i = C(i, n, o, s, t[a + 1], 5, -165796510), n, o, t[a + 6], 9, -1069501632), i, n, t[a + 11], 14, 643717713), s, i, t[a + 0], 20, -373897302), o = C(o, s = C(s, i = C(i, n, o, s, t[a + 5], 5, -701558691), n, o, t[a + 10], 9, 38016083), i, n, t[a + 15], 14, -660478335), s, i, t[a + 4], 20, -405537848), o = C(o, s = C(s, i = C(i, n, o, s, t[a + 9], 5, 568446438), n, o, t[a + 14], 9, -1019803690), i, n, t[a + 3], 14, -187363961), s, i, t[a + 8], 20, 1163531501), o = C(o, s = C(s, i = C(i, n, o, s, t[a + 13], 5, -1444681467), n, o, t[a + 2], 9, -51403784), i, n, t[a + 7], 14, 1735328473), s, i, t[a + 12], 20, -1926607734), o = N(o, s = N(s, i = N(i, n, o, s, t[a + 5], 4, -378558), n, o, t[a + 8], 11, -2022574463), i, n, t[a + 11], 16, 1839030562), s, i, t[a + 14], 23, -35309556), o = N(o, s = N(s, i = N(i, n, o, s, t[a + 1], 4, -1530992060), n, o, t[a + 4], 11, 1272893353), i, n, t[a + 7], 16, -155497632), s, i, t[a + 10], 23, -1094730640), o = N(o, s = N(s, i = N(i, n, o, s, t[a + 13], 4, 681279174), n, o, t[a + 0], 11, -358537222), i, n, t[a + 3], 16, -722521979), s, i, t[a + 6], 23, 76029189), o = N(o, s = N(s, i = N(i, n, o, s, t[a + 9], 4, -640364487), n, o, t[a + 12], 11, -421815835), i, n, t[a + 15], 16, 530742520), s, i, t[a + 2], 23, -995338651), o = E(o, s = E(s, i = E(i, n, o, s, t[a + 0], 6, -198630844), n, o, t[a + 7], 10, 1126891415), i, n, t[a + 14], 15, -1416354905), s, i, t[a + 5], 21, -57434055), o = E(o, s = E(s, i = E(i, n, o, s, t[a + 12], 6, 1700485571), n, o, t[a + 3], 10, -1894986606), i, n, t[a + 10], 15, -1051523), s, i, t[a + 1], 21, -2054922799), o = E(o, s = E(s, i = E(i, n, o, s, t[a + 8], 6, 1873313359), n, o, t[a + 15], 10, -30611744), i, n, t[a + 6], 15, -1560198380), s, i, t[a + 13], 21, 1309151649), o = E(o, s = E(s, i = E(i, n, o, s, t[a + 4], 6, -145523070), n, o, t[a + 11], 10, -1120210379), i, n, t[a + 2], 15, 718787259), s, i, t[a + 9], 21, -343485551),
                i = v(i, r),
                n = v(n, c),
                o = v(o, h),
                s = v(s, l)
        }
        return [i, n, o, s]
    }

    function _(t, e, i, n, o, s) {
        return v((a = v(v(e, t), v(n, s))) << (r = o) | a >>> 32 - r, i);
        var a, r
    }

    function S(t, e, i, n, o, s, a) {
        return _(e & i | ~e & n, t, e, o, s, a)
    }

    function C(t, e, i, n, o, s, a) {
        return _(e & n | i & ~n, t, e, o, s, a)
    }

    function N(t, e, i, n, o, s, a) {
        return _(e ^ i ^ n, t, e, o, s, a)
    }

    function E(t, e, i, n, o, s, a) {
        return _(i ^ (e | ~n), t, e, o, s, a)
    }

    function v(t, e) {
        var i = (65535 & t) + (65535 & e);
        return (t >> 16) + (e >> 16) + (i >> 16) << 16 | 65535 & i
    }
}
string = 'hello';
console.log(md5(string));

-1

এমনকি হ্যাশটি সুরক্ষার জন্য না হলেও আপনি এমডি 5 এর পরিবর্তে শা ব্যবহার করতে পারেন। আমার মতে, জনগণের আপাতত এমড 5 সম্পর্কে ভুলে যাওয়া উচিত, এটি অতীতে!

সাধারণ নোডেজ sha256 হ্রাস করা হয়। সুতরাং, আপনার জন্য এখন দুটি বিকল্প রয়েছে:

var shajs = require('sha.js')  - https://www.npmjs.com/package/sha.js (used by Browserify)

var hash = require('hash.js')  - https://github.com/indutny/hash.js

আমি এর shajsপরিবর্তে ব্যবহার করা পছন্দ করি hash, কারণ আমি আজকাল শা কে সেরা হ্যাশ ফাংশন হিসাবে বিবেচনা করি এবং আপাতত আপনার কোনও আলাদা হ্যাশ ফাংশন দরকার নেই। সুতরাং হেক্সে কিছু হ্যাশ পেতে আপনার নীচের মতো কিছু করা উচিত:

sha256.update('hello').digest('hex')
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.