public int DoFinal(byte[] output, int outOff) { int extra = bufOff; if (!forEncryption) { if (extra < macSize) throw new InvalidCipherTextException("data too short"); extra -= macSize; } if (extra > 0) { byte[] tmp = new byte[BlockSize]; Array.Copy(bufBlock, 0, tmp, 0, extra); gCTRBlock(tmp, extra, output, outOff); } // Final gHASH BigInteger X = BigInteger.ValueOf(A.Length * 8).ShiftLeft(64).Add( BigInteger.ValueOf(totalLength * 8)); //trace("len(A)||len(C): " + dumpBigInt(X)); S = multiply(S.Xor(X), H); //trace("GHASH(H,A,C): " + dumpBigInt(S)); // T = MSBt(GCTRk(J0,S)) byte[] tBytes = new byte[BlockSize]; cipher.ProcessBlock(J0, 0, tBytes, 0); //trace("E(K,Y0): " + new string(Hex.encode(tmp))); BigInteger T = S.Xor(new BigInteger(1, tBytes)); // TODO Fix this if tagLength becomes configurable byte[] tag = asBlock(T); //trace("T: " + new string(Hex.encode(tag))); int resultLen = extra; if (forEncryption) { this.macBlock = tag; Array.Copy(tag, 0, output, outOff + bufOff, tag.Length); resultLen += tag.Length; } else { this.macBlock = new byte[macSize]; Array.Copy(bufBlock, extra, macBlock, 0, macSize); if (!Arrays.AreEqual(tag, this.macBlock)) throw new InvalidCipherTextException("mac check in GCM failed"); } Reset(false); return resultLen; }
/// <summary> /// Generate a set of M-of-N parts for a specific private key. /// If desiredPrivKey is null, then a random key will be selected. /// </summary> public void Generate(int PartsNeededToDecode, int PartsToGenerate, byte[] desiredPrivKey) { if (PartsNeededToDecode > PartsToGenerate) { throw new ApplicationException("Number of parts needed exceeds number of parts to generate."); } if (PartsNeededToDecode > 8 || PartsToGenerate > 8) { throw new ApplicationException("Maximum number of parts is 8"); } if (PartsNeededToDecode < 1 || PartsToGenerate < 1) { throw new ApplicationException("Minimum number of parts is 1"); } if (desiredPrivKey != null && desiredPrivKey.Length != 32) { throw new ApplicationException("Desired private key must be 32 bytes"); } KeyParts.Clear(); decodedKeyParts.Clear(); SecureRandom sr = new SecureRandom(); // Get 8 random big integers into v[i]. byte[][] vvv = new byte[8][]; BigInteger[] v = new BigInteger[8]; for (int i = 0; i < 8; i++) { byte[] b = new byte[32]; sr.NextBytes(b, 0, 32); // For larger values of i, chop off some most-significant-bits to prevent overflows as they are // multiplied with increasingly larger factors. if (i >= 7) { b[0] &= 0x7f; } v[i] = new BigInteger(1, b); Debug.WriteLine(String.Format("v({0})={1}", i, v[i].ToString())); } // if a certain private key is desired, then specify it. if (desiredPrivKey != null) { // replace v[0] with xor(v[1...7]) xor desiredPrivKey BigInteger newv0 = BigInteger.Zero; for (int i=1; i<PartsNeededToDecode; i++) { newv0 = newv0.Xor(v[i]); } v[0] = newv0.Xor(new BigInteger(1,desiredPrivKey)); } // Generate the expected private key from all the parts BigInteger privkey = new BigInteger("0"); for (int i = 0; i < PartsNeededToDecode; i++) { privkey = privkey.Xor(v[i]); } // Get the bitcoin address byte[] keybytes = privkey.ToByteArrayUnsigned(); // make sure we have 32 bytes, we'll need it if (keybytes.Length < 32) { byte[] array32 = new byte[32]; Array.Copy(keybytes, 0, array32, 32 - keybytes.Length, keybytes.Length); keybytes = array32; } KeyPair = new KeyPair(keybytes); byte[] checksum = Util.ComputeSha256(BitcoinAddress); // Generate the parts for (int i = 0; i < PartsToGenerate; i++) { BigInteger total = new BigInteger("0"); for (int j = 0; j < PartsNeededToDecode; j++) { int factor = 1; for (int ii = 0; ii <= i; ii++) factor = factor * (j + 1); BigInteger bfactor = new BigInteger(factor.ToString()); total = total.Add(v[j].Multiply(bfactor)); } Debug.WriteLine(String.Format(" pc{0}={1}", i, total.ToString())); byte[] parts = new byte[39]; parts[0] = 0x4f; parts[1] = (byte)(0x93 + PartsNeededToDecode); int parts23 = (((checksum[0] << 8) + checksum[1]) & 0x1ff); Debug.WriteLine("checksum " + parts23.ToString()); parts23 += 0x6000; parts23 += (i << 9); byte[] btotal = total.ToByteArrayUnsigned(); for (int jj = 0; jj < btotal.Length; jj++) { parts[jj + 4 + (35 - btotal.Length)] = btotal[jj]; } parts[2] = (byte)((parts23 & 0xFF00) >> 8); parts[3] = (byte)(parts23 & 0xFF); KeyParts.Add(Util.ByteArrayToBase58Check(parts)); decodedKeyParts.Add(parts); } }