নোড.জেজে আইডি হিসাবে ব্যবহার করতে এলোমেলোভাবে SHA1 হ্যাশ কীভাবে তৈরি করা যায়?


137

আমি এই লাইনটি নোড.জেএস এর জন্য একটি শ 1 আইডি উত্পন্ন করতে ব্যবহার করছি:

crypto.createHash('sha1').digest('hex');

সমস্যাটি হ'ল এটি প্রতিবার একই আইডি ফিরছে।

এটি কি প্রতিবার একটি এলোমেলো আইডি তৈরি করা সম্ভব যাতে আমি এটি একটি ডাটাবেস নথি আইডি হিসাবে ব্যবহার করতে পারি?


2
Sha1 ব্যবহার করবেন না। এটি আর নিরাপদ হিসাবে বিবেচিত হয় না (সংঘর্ষ-প্রতিরোধী)। এই কারণেই নওমিকের উত্তর আরও ভাল।
নীলস অ্যাবিল্ডগার্ড

উত্তর:


60

এখানে একবার দেখুন: HMAC-SHA1 হ্যাশ তৈরি করতে আমি কীভাবে নোড.জেএস ক্রিপ্টো ব্যবহার করব? হ্যাশের স্বাতন্ত্র্যতা নিশ্চিত করতে আমি বর্তমান টাইমস্ট্যাম্প + একটি এলোমেলো সংখ্যার একটি হ্যাশ তৈরি করব:

var current_date = (new Date()).valueOf().toString();
var random = Math.random().toString();
crypto.createHash('sha1').update(current_date + random).digest('hex');

44
আরও ভাল পদ্ধতির জন্য নীচে @ নওমিকের উত্তর দেখুন।
গবি পুরকারু

2
এটি একটি দুর্দান্ত উত্তর গবিও ছিল, এবং কেবলমাত্র একটি সামান্য কিছুটা দ্রুত, প্রায় 15%। দু'জনেই দুর্দান্ত কাজ! আমি প্রকৃতপক্ষে লবনের একটি তারিখ () দেখতে চাই, এটি বিকাশকারীকে সহজ আত্মবিশ্বাস দেয় যে এটি সবচেয়ে পাগল সমান্তরাল কম্পিউটিং পরিস্থিতি বাদে সকলের ক্ষেত্রেই অনন্য মূল্য। আমি জানি এর নির্বোধ এবং র্যান্ডমবাইটগুলি (20) অনন্য হতে চলেছে, তবে এটির কেবল একটি আস্থা আমাদের থাকতে পারে কারণ আমরা অন্য লাইব্রেরির এলোমেলো প্রজন্মের অভ্যন্তরের সাথে পরিচিত হতে পারি না।
দিমিত্রি আর 117

636

243,583,606,221,817,150,598,111,409x আরও এনট্রপি

আমি crypto.randomBytes ব্যবহার করার পরামর্শ দিই । এটি নয় sha1, আইডি উদ্দেশ্যে, এটি দ্রুত এবং ঠিক "এলোমেলো"।

var id = crypto.randomBytes(20).toString('hex');
//=> f26d60305dae929ef8640a75e70dd78ab809cfe9

ফলস্বরূপ স্ট্রিংটি আপনার এলোমেলো বাইটগুলি দ্বিগুণ হবে; হেক্সে এনকোড করা প্রতিটি বাইট 2 টি অক্ষর। 20 বাইট হেক্সের 40 টি অক্ষর হবে।

20 বাইট ব্যবহার করে আমাদের 256^20বা 1,461,501,637,330,902,918,203,684,832,716,283,019,655,932,542,976 অনন্য আউটপুট মান রয়েছে। এটি SHA1 এর 160-বিট (20-বাইট) সম্ভাব্য আউটপুটগুলির সাথে সমান

এটি জানার পরে, এটি shasumআমাদের এলোমেলো বাইটের কাছে সত্যই অর্থবহ নয় । এটি দু'বার ডাই রোল করার মতো তবে কেবল দ্বিতীয় রোল গ্রহণ করা; যাই হোক না কেন, আপনার প্রতিটি রোলের 6 টি সম্ভাব্য ফলাফল রয়েছে, তাই প্রথম রোল যথেষ্ট।


কেন এই ভাল?

এটি আরও ভাল কেন তা বুঝতে, আমাদের প্রথমে হ্যাশিং ফাংশনগুলি কীভাবে কাজ করে তা বুঝতে হবে। হ্যাশিং ফাংশনগুলি (এসএএএ 1 সহ) সর্বদা একই আউটপুট উত্পন্ন করে যদি একই ইনপুট দেওয়া হয়।

বলুন আমরা আইডি জেনারেট করতে চাই তবে আমাদের এলোমেলো ইনপুটটি একটি কয়েন টস দ্বারা উত্পন্ন। আমাদের আছে "heads"বা"tails"

% echo -n "heads" | shasum
c25dda249cdece9d908cc33adcd16aa05e20290f  -

% echo -n "tails" | shasum
71ac9eed6a76a285ae035fe84a251d56ae9485a4  -

তাহলে "heads"আবার আসে, SHA1 এ আউটপুট হবে একই হিসাবে এটি প্রথম সময় ছিল

% echo -n "heads" | shasum
c25dda249cdece9d908cc33adcd16aa05e20290f  -

ঠিক আছে, সুতরাং একটি কয়েন টস দুর্দান্ত র্যান্ডম আইডি জেনারেটর নয় কারণ আমাদের কাছে কেবল দুটি সম্ভাব্য আউটপুট রয়েছে।

যদি আমরা একটি স্ট্যান্ডার্ড 6-পার্শ্বযুক্ত ডাই ব্যবহার করি তবে আমাদের 6 টি সম্ভাব্য ইনপুট রয়েছে। অনুমান করুন কতগুলি সম্ভব SHA1 আউটপুট? 6!

input => (sha1) => output
1 => 356a192b7913b04c54574d18c28d46e6395428ab
2 => da4b9237bacccdf19c0760cab7aec4a8359010b0
3 => 77de68daecd823babbb58edb1c8e14d7106e83bb
4 => 1b6453892473a467d07372d45eb05abc2031647a
5 => ac3478d69a3c81fa62e60f5c3696165a4e5e6ac4
6 => c1dfd96eea8cc2b62785275bca38ac261256e278

এটা ঠিক, কারণ আমাদের ফাংশনের আউটপুট চিন্তা করে নিজেদেরকে প্রতারিত করা সহজ সৌন্দর্য , খুব এলোমেলো এটি হল খুব র্যান্ডম।

আমরা উভয়ই একমত যে একটি কয়েন টস বা 6-পার্শ্বের ডাই একটি খারাপ এলোমেলো আইডি জেনারেটর তৈরি করবে, কারণ আমাদের সম্ভাব্য SHA1 ফলাফল (আইডির জন্য আমরা যে মানটি ব্যবহার করি) খুব কম। তবে আমরা যদি এমন কিছু ব্যবহার করি যার আরও অনেক আউটপুট থাকে? মিলিসেকেন্ডের সাথে টাইমস্ট্যাম্পের মতো? নাকি জাভাস্ক্রিপ্ট Math.random? নাকি এই দুজনের সংমিশ্রণ ?!

আসুন আমরা কতগুলি অনন্য আইডি পেতে পারি তা গণনা করা যাক ...


মিলিসেকেন্ড সহ টাইমস্ট্যাম্পের স্বতন্ত্রতা

ব্যবহার করার সময় (new Date()).valueOf().toString(), আপনি একটি 13-অক্ষর নম্বর পেয়ে যাচ্ছেন (যেমন, 1375369309741)। তবে এটি যেহেতু ধারাবাহিকভাবে আপডেট করার সংখ্যা (একবারে প্রতি মিলিসেকেন্ডে), ফলাফলগুলি প্রায় সর্বদা একই থাকে। এর কটাক্ষপাত করা যাক

for (var i=0; i<10; i++) {
  console.log((new Date()).valueOf().toString());
}
console.log("OMG so not random");

// 1375369431838
// 1375369431839
// 1375369431839
// 1375369431839
// 1375369431839
// 1375369431839
// 1375369431839
// 1375369431839
// 1375369431840
// 1375369431840
// OMG so not random

সুষ্ঠু হতে, তুলনা উদ্দেশ্যে, একটি নির্দিষ্ট মিনিটে (একটি উদার অপারেশন কার্যকর করার সময়), আপনি 60*1000বা 60000অদ্ভুত হবে।


এর স্বতন্ত্রতা Math.random

এখন, ব্যবহার করার সময় Math.random, জাভাস্ক্রিপ্ট যেভাবে flo৪-বিট ভাসমান পয়েন্ট সংখ্যা উপস্থাপন করে, আপনি 13 এবং 24 অক্ষরের মধ্যে দৈর্ঘ্যের দৈর্ঘ্যের সংখ্যা পাবেন get দীর্ঘ ফলাফলের অর্থ আরও বেশি অঙ্ক যার অর্থ আরও এনট্রপি। প্রথমত, আমাদের সর্বাধিক সম্ভাব্য দৈর্ঘ্যটি খুঁজে বের করতে হবে।

নীচের স্ক্রিপ্টটি নির্ধারণ করবে কোন দৈর্ঘ্যটি সবচেয়ে সম্ভাব্য। আমরা 1 মিলিয়ন এলোমেলো সংখ্যা উত্পন্ন করে .lengthএবং প্রতিটি সংখ্যার উপর ভিত্তি করে একটি কাউন্টার বাড়িয়ে এটি করি ।

// get distribution
var counts = [], rand, len;
for (var i=0; i<1000000; i++) {
  rand = Math.random();
  len  = String(rand).length;
  if (counts[len] === undefined) counts[len] = 0;
  counts[len] += 1;
}

// calculate % frequency
var freq = counts.map(function(n) { return n/1000000 *100 });

প্রতিটি কাউন্টারকে 1 মিলিয়ন দিয়ে ভাগ করে, আমরা সংখ্যার দৈর্ঘ্য থেকে ফিরে আসার সম্ভাবনা পাই Math.random

len   frequency(%)
------------------
13    0.0004  
14    0.0066  
15    0.0654  
16    0.6768  
17    6.6703  
18    61.133  <- highest probability
19    28.089  <- second highest probability
20    3.0287  
21    0.2989  
22    0.0262
23    0.0040
24    0.0004

সুতরাং, যদিও এটি সম্পূর্ণ সত্য নয়, আসুন উদার হন এবং বলুন যে আপনি 19-চরিত্রের দীর্ঘ এলোমেলো আউটপুট পান; 0.1234567890123456789। প্রথম অক্ষর সর্বদা থাকবে 0এবং .তাই সত্যই আমরা কেবল 17 টি এলোমেলো অক্ষর পাচ্ছি। এটি আমাদের 10^17 +1(সম্ভাব্যর জন্য 0; নীচের নোটগুলি দেখুন) বা 100,000,000,000,000,001 টি অসুবিধায় ফেলেছে leaves


সুতরাং আমরা কত এলোমেলো ইনপুট তৈরি করতে পারি?

ঠিক আছে, আমরা মিলিসেকেন্ড টাইমস্ট্যাম্পের জন্য ফলাফলের সংখ্যা গণনা করেছি Math.random

      100,000,000,000,000,001 (Math.random)
*                      60,000 (timestamp)
-----------------------------
6,000,000,000,000,000,060,000

এটি একক 6,000,000,000,000,000,060,000-পক্ষীয় ডাই। অথবা, এই সংখ্যাটি আরও মানবিকভাবে হজমযোগ্য করতে, এটি প্রায় একই সংখ্যার

input                                            outputs
------------------------------------------------------------------------------
( 1×) 6,000,000,000,000,000,060,000-sided die    6,000,000,000,000,000,060,000
(28×) 6-sided die                                6,140,942,214,464,815,497,21
(72×) 2-sided coins                              4,722,366,482,869,645,213,696

বেশ ভাল লাগছে, তাইনা? ঠিক আছে, আসুন জেনে নেওয়া যাক ...

SHA1 একটি সম্ভাব্য 256 ^ 20 ফলাফল সহ 20-বাইট মান উত্পাদন করে। সুতরাং আমরা সত্যিই এটির সম্পূর্ণ সম্ভাবনার জন্য SHA1 ব্যবহার করছি না। আচ্ছা আমরা কতটা ব্যবহার করছি?

node> 6000000000000000060000 / Math.pow(256,20) * 100

একটি মিলিসেকেন্ড টাইমস্ট্যাম্প এবং ম্যাথ.রান্ডম SHA1 এর 160-বিট সম্ভাবনার মাত্র 4.11e-27 শতাংশ ব্যবহার করে!

generator               sha1 potential used
-----------------------------------------------------------------------------
crypto.randomBytes(20)  100%
Date() + Math.random()    0.00000000000000000000000000411%
6-sided die               0.000000000000000000000000000000000000000000000411%
A coin                    0.000000000000000000000000000000000000000000000137%

পবিত্র বিড়াল, মানুষ! এই সমস্ত শূন্যের দিকে তাকান। তাহলে আর কত ভাল crypto.randomBytes(20)? 243,583,606,221,817,150,598,111,409 গুণ ভাল।


+1শূন্যগুলির ফ্রিকোয়েন্সি এবং সম্পর্কে নোটস

আপনি যদি ভাবছেন তবে +1এটির Math.randomপক্ষে ফিরে আসা সম্ভব 0যার অর্থ আমাদের আরও 1 টি অনন্য ফলাফলের জন্য জবাবদিহি করতে হবে।

নীচে ঘটে যাওয়া আলোচনার ভিত্তিতে আমি কৌতূহল ছিল যে এ 0কীভাবে আসবে তা সম্পর্কে । এখানে একটি ছোট স্ক্রিপ্ট, random_zero.jsআমি কিছু ডেটা পেতে তৈরি করেছি

#!/usr/bin/env node
var count = 0;
while (Math.random() !== 0) count++;
console.log(count);

তারপরে, আমি এটিকে 4 টি থ্রেডে চালিয়েছি (আমার কাছে একটি 4-কোর প্রসেসর রয়েছে), আউটপুটটিকে কোনও ফাইলে সংযুক্ত করে

$ yes | xargs -n 1 -P 4 node random_zero.js >> zeroes.txt

সুতরাং এটি সক্রিয় যে একটি 0পেতে খুব কঠিন নয়। 100 মান রেকর্ড করার পরে , গড় ছিল

3,164,854,823 এলোমেলোতে 1 টি 0

শান্ত! এই সংখ্যাটি ভি 8 এর Math.randomবাস্তবায়নের অভিন্ন বিতরণের সাথে সমান কিনা তা জানতে আরও গবেষণার প্রয়োজন হবে


2
দয়া করে আমার আপডেট দেখুন; এমনকি একটি মিলিসেকেন্ড লাইটস্পিড জাভাস্ক্রিপ্ট জমিতে দীর্ঘ সময়! আরও গুরুতর নোটে, সংখ্যার প্রথম 10 টি সংখ্যা প্রতি সেকেন্ডে একই থাকে; এটিই Dateভাল বীজ উত্পাদন করতে ভয়ঙ্কর করে তোলে ।
আপনাকে ধন্যবাদ

1
সঠিক। যদিও আমি সত্যিই কেবল এটিকে অন্তর্ভুক্ত করে অন্য জবাবকে সর্বোচ্চ অবদানের জন্য এটি দেখিয়েছি যে 20 এলোমেলো বাইটগুলি এখনও এন্ট্রপির ক্ষেত্রে কেবল প্রাধান্য পেয়েছে। আমি Math.randomকখনও মনে করি না যে একটি উত্পাদন করবে0.
আপনাকে ধন্যবাদ

8
স্বীকৃত উত্তরের চেয়ে 14x আরও উচ্চতর ... তবে কে গণনা করছে? :)
zx81

2
@moka, পাশা বহুবচন রূপ ডাই । আমি একবচন ফর্ম ব্যবহার করছি।
আপনাকে ধন্যবাদ

2
crypto.randomBytesঅবশ্যই যাওয়ার উপায় ^^
আপনাকে

28

এটি ব্রাউজারেও করুন!

সম্পাদনা: এটি আমার পূর্ববর্তী উত্তরের প্রবাহের সাথে খাপ খায় না। আমি এটি এখানে লোকদের দ্বিতীয় উত্তর হিসাবে রেখে যাচ্ছি যা সম্ভবত ব্রাউজারে এটি করার জন্য খুঁজছেন।

আপনি চাইলে আধুনিক ব্রাউজারগুলিতে এই ক্লায়েন্টের পক্ষে করতে পারেন

// str byteToHex(uint8 byte)
//   converts a single byte to a hex string 
function byteToHex(byte) {
  return ('0' + byte.toString(16)).slice(-2);
}

// str generateId(int len);
//   len - must be an even number (default: 40)
function generateId(len = 40) {
  var arr = new Uint8Array(len / 2);
  window.crypto.getRandomValues(arr);
  return Array.from(arr, byteToHex).join("");
}

console.log(generateId())
// "1e6ef8d5c851a3b5c5ad78f96dd086e4a77da800"

console.log(generateId(20))
// "d2180620d8f781178840"

ব্রাউজার প্রয়োজনীয়তা

Browser    Minimum Version
--------------------------
Chrome     11.0
Firefox    21.0
IE         11.0
Opera      15.0
Safari     5.1

3
Number.toString(radix)সর্বদা 2 ডিজিটের মান গ্যারান্টি দেয় না (উদা: (5).toString(16)= "5", "05" নয়)। আপনি চূড়ান্ত lenঅক্ষর দীর্ঘ হতে আপনার চূড়ান্ত আউটপুট উপর নির্ভর করে যদি না এটি বিবেচ্য নয় । এই ক্ষেত্রে আপনি return ('0'+n.toString(16)).slice(-2);আপনার মানচিত্রের ফাংশনটির অভ্যন্তর ব্যবহার করতে পারেন ।
ব্র্যাভিনি ম্যান

1
দুর্দান্ত কোড, ধন্যবাদ। কেবল যোগ করতে চেয়েছিলেন: আপনি যদি এটি কোনও idগুণকের মানটির জন্য ব্যবহার করতে চলেছেন তবে নিশ্চিত করুন যে আইডিটি কোনও চিঠি দিয়ে শুরু হয়েছে: [এ-জা-জেড]।
গিজসনবি

দুর্দান্ত উত্তর (এবং মন্তব্য) - সত্যই আপনি প্রশংসা করেছেন যে আপনি উত্তরে ব্রাউজারের প্রয়োজনীয়তাও অন্তর্ভুক্ত করেছেন!
কেভলার

ব্রাউজারের প্রয়োজনীয়তাগুলি ভুল। অ্যারে.ফ্রম () IE11 এ সমর্থিত নয়
প্রিফিক্স

1
এই উত্তর দেওয়ার সময় এটি একটি উইকি থেকে নেওয়া হয়েছিল। আপনি চাইলে আপনি এই উত্তরটি সম্পাদনা করতে পারেন, তবে প্রকৃতপক্ষে কে IE সম্পর্কে চিন্তা করে? আপনি যদি এটি সমর্থন করার চেষ্টা করছেন, আপনাকে যাইহোক জাভাস্ক্রিপ্টের অর্ধেক পলিফিল করতে হবে ...
ধন্যবাদ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.