├── .gitignore ├── LICENSE ├── README.md ├── generate.js ├── package.json ├── vanity.js └── wallet.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .idea 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Mike Boremi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Offline Ethereum (Classic) Generator 2 | 3 | ## Requirements 4 | 5 | * nodejs 6 | 7 | ## Installation 8 | 9 | ``` 10 | git clone https://github.com/mikeyb/offline-etc-generator.git 11 | 12 | cd offline-etc-generator 13 | 14 | npm install 15 | ``` 16 | 17 | ## Usage 18 | 19 | #### Generate random keys 20 | `node generate` 21 | 22 | #### Generate vanity address 23 | `node vanity` 24 | 25 | ## Example 26 | 27 | ``` 28 | $ node generate mew ✭ ✚ ✱ 29 | 30 | ! DO NOT FORGET THIS PASSWORD ! 31 | ! DO NOT FORGET THIS PASSWORD ! 32 | 33 | 34 | Password: ¤¤¤¤¤¤¤¤¤¤ 35 | 36 | 37 | ====WALLET KEYS==== 38 | 39 | Geth Encrypted Private Key {"version":3,"id":"c2337130-2099-4f23-93fb-bdf7495d8ebd","address":"888b2951816c71c9ea32ef941328911c6041aad1","Crypto":{"ciphertext":"7bd81b31ad9a1350ada8001f5be7bb61ac7e8e3506fa2e4249e2bd103e46cc5c","cipherparams":{"iv":"aaa568a9da472f6dbbd94ea62fe09077"},"cipher":"aes-128-ctr","kdf":"pbkdf2","kdfparams":{"dklen":32,"salt":"6abc743b5262776787453e4f90edc67707a29d513c7b3d631bbc743b55f68ae1","c":262144,"prf":"hmac-sha256"},"mac":"b15b7d403cafcddea67dfb2c9910b58038bbcd75777ef08c9e247a1c601abc48"}} 40 | Private Key be736ee17fcbbc94e11c2d3759af31ac60eb53e95b9b3c3d66836b3b02c3a4c9 41 | Public Key 0x233520f70dcca9e152f60475e40a3fc8fb2b1e34b96cae67e41398e7fed951ff0c9dde93bcb5b9d390ccac4fb208d4674ffa113870f94d278715ef2fa2511c82 42 | Address 0x888b2951816c71c9ea32ef941328911c6041aad1 43 | 44 | ====IMPORT WALLET==== 45 | 46 | Geth Encrypted Private Key 47 | 48 | Save to a file inside DATADIR/keystore/ 49 | 50 | DATADIR is where your geth is configured to store data. 51 | See: https://github.com/ethereumproject/go-ethereum/wiki/Backup-&-restore 52 | 53 | Unlock with the password you entered above using geth --unlock 888b2951816c71c9ea32ef941328911c6041aad1 console 54 | 55 | Private Key 56 | 57 | Save to a file and run geth account import filename 58 | 59 | You should DELETE this file after successful import! 60 | 61 | ====WARNING==== 62 | 63 | !!! BEFORE SENDING TOKENS TO WALLET, VERIFY IT UNLOCKS !!! 64 | 65 | You have been warned. The creator of this software accepts NO RESPONSIBILITY. 66 | 67 | By using the data above, you agree that YOU ARE RESPONSIBLE for anything that happens. 68 | 69 | ====DONATION INFORMATION==== 70 | 71 | ETC 2999ed06ee503402c5a0b57143d709cfae9ce695 72 | ETH 7e0e7e1a4aaf80db1e72528e29c72cd8b36a66de 73 | BTC 1FpxPPXXonXudUbid1GbXmBuhBoRQU7agT 74 | ``` 75 | -------------------------------------------------------------------------------- /generate.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var chalk = require('chalk'); 4 | var prompt = require('prompt'); 5 | var Wallet = require('./wallet'); 6 | 7 | var getChalk = function (type, msg) { 8 | 9 | switch (type) { 10 | case "alertText": 11 | return chalk.bgRed.white(msg); 12 | break; 13 | case "infoText": 14 | return chalk.bgBlack.green(msg); 15 | break; 16 | }; 17 | 18 | }; 19 | 20 | var divider = getChalk('alertText', '===='); 21 | 22 | console.log('\n' + getChalk('alertText', '! DO NOT FORGET THIS PASSWORD !')); 23 | console.log(getChalk('alertText', '! DO NOT FORGET THIS PASSWORD !')); 24 | console.log('\n'); 25 | 26 | prompt.message = getChalk('infoText', ''); 27 | 28 | prompt.start(); 29 | 30 | prompt.get([{ 31 | 32 | hidden: true, 33 | required: true, 34 | type: 'string', 35 | name: 'password', 36 | replace: '\u00A4', 37 | pattern: /^.{9,200}$/, 38 | message: 'Password must be > 9 characters', 39 | description: getChalk('infoText', 'Password') 40 | 41 | 42 | }], function (err, result) { 43 | 44 | var myWallet = Wallet.generate(); 45 | var myV3 = myWallet.toV3String(result.password); 46 | var myPrivateKey = myWallet.getPrivateKeyString(); 47 | var myPublicKey = myWallet.getPublicKeyString(); 48 | var myAddress = myWallet.getAddressString(); 49 | 50 | console.log('\n' + divider + getChalk('infoText', 'WALLET KEYS') + divider); 51 | console.log('\n' + getChalk('infoText', 'Geth Encrypted Private Key') + ' ' + myV3); 52 | console.log(getChalk('infoText', 'Private Key') + ' ' + myPrivateKey); 53 | console.log(getChalk('infoText', 'Public Key') + ' ' + myPublicKey); 54 | console.log(getChalk('infoText', 'Address') + ' ' + myAddress); 55 | console.log('\n' + divider + getChalk('infoText', 'IMPORT WALLET') + divider); 56 | console.log('\n' + getChalk('infoText', 'Geth Encrypted Private Key')); 57 | console.log('\n Save to a file inside ' + getChalk('infoText', 'DATADIR/keystore/')); 58 | console.log('\n DATADIR is where your geth is configured to store data.'); 59 | console.log(' See: https://github.com/ethereumproject/go-ethereum/wiki/Backup-&-restore'); 60 | console.log('\n Unlock with the password you entered above using ' + getChalk('infoText', 'geth --unlock ' + myAddress.substr(2) + ' console')); 61 | console.log('\n' + getChalk('infoText', 'Private Key')); 62 | console.log('\n Save to a file and run ' + getChalk('infoText', 'geth account import filename')); 63 | console.log('\n You should DELETE this file after successful import!'); 64 | console.log('\n' + divider + getChalk('infoText', 'WARNING') + divider); 65 | console.log('\n' + getChalk('alertText', '!!! BEFORE SENDING TOKENS TO WALLET, VERIFY IT UNLOCKS !!!')); 66 | console.log('\nYou have been warned. The creator of this software accepts NO RESPONSIBILITY.'); 67 | console.log('\nBy using the data above, you agree that YOU ARE RESPONSIBLE for anything that happens.'); 68 | console.log('\n' + divider + getChalk('infoText', 'DONATION INFORMATION') + divider); 69 | console.log('\n ' + getChalk('infoText', 'ETC') + ' 2999ed06ee503402c5a0b57143d709cfae9ce695'); 70 | console.log(' ' + getChalk('infoText', 'ETH') + ' 7e0e7e1a4aaf80db1e72528e29c72cd8b36a66de'); 71 | console.log(' ' + getChalk('infoText', 'BTC') + ' 1FpxPPXXonXudUbid1GbXmBuhBoRQU7agT\n'); 72 | 73 | }); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "offline-etc-generator", 3 | "version": "1.2.0", 4 | "description": "Generate an Ethereum private/public key and corresponding address", 5 | "main": "", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/mikeyb/offline-etc-generator.git" 9 | }, 10 | "keywords": [ 11 | "classic", 12 | "ethereum", 13 | "immutable", 14 | "original", 15 | "utilties", 16 | "wallet" 17 | ], 18 | "author": "Mike Boremi ", 19 | "contributors": [{ 20 | "name": "Seth", 21 | "github": "https://github.com/sethfork" 22 | }], 23 | "license": "MIT", 24 | "bugs": { 25 | "url": "https://github.com/mikeyb/offline-etc-generator/issues" 26 | }, 27 | "homepage": "https://github.com/mikeyb/offline-etc-generator", 28 | "dependencies": { 29 | "ethereumjs-util": "^4.5.0", 30 | "bn.js": "^4.8.0", 31 | "create-hash": "^1.1.2", 32 | "keccakjs": "^0.2.0", 33 | "rlp": "^2.0.0", 34 | "secp256k1": "^3.0.1", 35 | "uuid": "^2.0.2", 36 | "scryptsy": "^2.0.0", 37 | "prompt": "^1.0.0", 38 | "chalk": "^1.1.3" 39 | }, 40 | "devDependencies": { 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /vanity.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var prompt = require('prompt'); 4 | var Wallet = require('./wallet'); 5 | 6 | var attempts = 0; 7 | 8 | prompt.start(); 9 | 10 | prompt.get([{ 11 | 12 | required: true, 13 | type: 'string', 14 | name: 'addressString', 15 | pattern: /^[0-9a-f]{1,40}$/, 16 | message: 'Addresses can only contain [0-9a-fA-F] characters', 17 | description: 'Vanity Address To Generate' 18 | 19 | 20 | }], function (err, result) { 21 | 22 | console.log('Trying to crack: ' + result.addressString); 23 | 24 | while (true) { 25 | 26 | var myWallet = Wallet.generate(); 27 | 28 | var myAddress = myWallet.getAddressString().substr(2); 29 | 30 | var vanityLength = result.addressString.length; 31 | 32 | if (myAddress.substr(0,vanityLength) == result.addressString) { 33 | 34 | console.log('\nVanity Address Found: 0x' + myAddress); 35 | 36 | console.log('Vanity Key: ' + myWallet.getPrivateKeyString()); 37 | 38 | break; 39 | 40 | }; 41 | 42 | }; 43 | 44 | }); 45 | -------------------------------------------------------------------------------- /wallet.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var crypto = require('crypto'); 4 | var ethUtils = require('ethereumjs-util'); 5 | var uuid = require('uuid'); 6 | 7 | var Wallet = function(pk) { 8 | this.privateKey = pk.length == 32 ? pk : Buffer(pk, 'hex'); 9 | }; 10 | 11 | Wallet.generate = function() { 12 | return new Wallet(crypto.randomBytes(32)); 13 | }; 14 | 15 | Wallet.prototype.getPrivateKey = function() { 16 | return this.privateKey; 17 | }; 18 | 19 | Wallet.prototype.getPrivateKeyString = function() { 20 | return this.getPrivateKey().toString('hex'); 21 | }; 22 | 23 | Wallet.prototype.getPublicKey = function() { 24 | return ethUtils.privateToPublic(this.privateKey); 25 | }; 26 | 27 | Wallet.prototype.getPublicKeyString = function() { 28 | return '0x' + this.getPublicKey().toString('hex'); 29 | }; 30 | 31 | Wallet.prototype.getAddress = function() { 32 | return ethUtils.privateToAddress(this.privateKey); 33 | }; 34 | 35 | Wallet.prototype.getAddressString = function() { 36 | return '0x' + this.getAddress().toString('hex'); 37 | }; 38 | 39 | Wallet.prototype.getChecksumAddressString = function() { 40 | return ethUtils.toChecksumAddress(this.getAddressString()); 41 | }; 42 | 43 | Wallet.fromPrivateKey = function(pk) { 44 | return new Wallet(pk); 45 | }; 46 | 47 | Wallet.prototype.toV3 = function(password) { 48 | var opts = {}; 49 | var salt = crypto.randomBytes(32); 50 | var iv = crypto.randomBytes(16); 51 | var kdf = 'pbkdf2'; 52 | var kdfparams = { 53 | dklen: 32, 54 | salt: salt.toString('hex'), 55 | c: 1048576, 56 | prf: 'hmac-sha256' 57 | }; 58 | var derivedKey = crypto.pbkdf2Sync(new Buffer(password), salt, kdfparams.c, kdfparams.dklen, 'sha256'); 59 | var cipher = crypto.createCipheriv('aes-128-ctr', derivedKey.slice(0, 16), iv); 60 | var ciphertext = Buffer.concat([cipher.update(this.privateKey), cipher.final()]); 61 | var mac = ethUtils.sha3(Buffer.concat([derivedKey.slice(16, 32), new Buffer(ciphertext, 'hex')])); 62 | return { 63 | version: 3, 64 | id: uuid.v4({ 65 | random: crypto.randomBytes(16) 66 | }), 67 | address: this.getAddress().toString('hex'), 68 | Crypto: { 69 | ciphertext: ciphertext.toString('hex'), 70 | cipherparams: { 71 | iv: iv.toString('hex') 72 | }, 73 | cipher: 'aes-128-ctr', 74 | kdf: kdf, 75 | kdfparams: kdfparams, 76 | mac: mac.toString('hex') 77 | } 78 | }; 79 | }; 80 | 81 | Wallet.prototype.toV3String = function(password) { 82 | return JSON.stringify(this.toV3(password)) 83 | }; 84 | 85 | module.exports = Wallet; --------------------------------------------------------------------------------