public static void InitRC4Encryption(byte[] secretKey, byte[] pubKeyIn, int inOffset, byte[] pubKeyOut, int outOffset, out byte[] rc4keyIn, out byte[] rc4keyOut) { byte[] digest = new byte[RTMPConst.SHA256_DIGEST_LENGTH]; System.Security.Cryptography.HMAC hmac = System.Security.Cryptography.HMACSHA256.Create("HMACSHA256"); hmac.Key = secretKey; byte[] actualpubKeyIn = new byte[128]; Array.Copy(pubKeyIn, inOffset, actualpubKeyIn, 0, 128); digest = hmac.ComputeHash(actualpubKeyIn); rc4keyOut = new byte[16]; Array.Copy(digest, rc4keyOut, 16); LibRTMPLogger.Log(LibRTMPLogLevel.Trace, "[CDR.LibRTMP.RTMPHelper] RC4 Out Key: "); LibRTMPLogger.LogHex(LibRTMPLogLevel.Trace, rc4keyOut, 0, 16); hmac = System.Security.Cryptography.HMACSHA256.Create("HMACSHA256"); hmac.Key = secretKey; byte[] actualpubKeyOut = new byte[128]; Array.Copy(pubKeyOut, outOffset, actualpubKeyOut, 0, 128); digest = hmac.ComputeHash(actualpubKeyOut); rc4keyIn = new byte[16]; Array.Copy(digest, rc4keyIn, 16); LibRTMPLogger.Log(LibRTMPLogLevel.Trace, "[CDR.LibRTMP.RTMPHelper] RC4 In Key: "); LibRTMPLogger.LogHex(LibRTMPLogLevel.Trace, rc4keyIn, 0, 16); }
public void Dump(LibRTMPLogLevel loglevel = LibRTMPLogLevel.Trace) { if (type == AMFDataType.AMF_INVALID) { LibRTMPLogger.Log(loglevel, "AMFObjectProperty.Dump: Property: INVALID"); return; } if (type == AMFDataType.AMF_NULL) { LibRTMPLogger.Log(loglevel, "AMFObjectProperty.Dump: Property: NULL"); return; } if (type == AMFDataType.AMF_OBJECT) { LibRTMPLogger.Log(loglevel, "AMFObjectProperty.Dump : Property: OBJECT ====>"); objVal.Dump(); return; } string strRes = "no-name. "; if (stringName != string.Empty) { strRes = "Name: " + stringName + ", "; } string strVal; switch (type) { case AMFDataType.AMF_NUMBER: strVal = string.Format("NUMBER: {0}", numVal); break; case AMFDataType.AMF_BOOLEAN: strVal = string.Format("BOOLEAN: {0}", numVal == 1.0 ? "TRUE" : "FALSE"); break; case AMFDataType.AMF_STRING: strVal = string.Format("STRING: {0}", stringVal.Length < 256 ? stringVal : "Length: " + stringVal.Length.ToString()); break; default: strVal = string.Format("INVALID TYPE {0}", type); break; } //switch strRes += strVal; LibRTMPLogger.Log(loglevel, string.Format("Property: {0}", strRes)); }
public static uint GetDHOffset2(byte[] handshake, int bufferoffset, uint len) { uint offset = 0; bufferoffset += 768; offset += handshake[bufferoffset]; bufferoffset++; offset += handshake[bufferoffset]; bufferoffset++; offset += handshake[bufferoffset]; bufferoffset++; offset += handshake[bufferoffset]; uint res = (offset % 632) + 8; if (res + 128 > 767) { string msg = string.Format("[CDR.LibRTMP.RTMPHelper] Couldn't calculate correct DH offset (got {0}), exiting!", res); LibRTMPLogger.Log(LibRTMPLogLevel.Warning, msg); throw new Exception(msg); } return(res); }
public static uint GetDigestOffset2(byte[] handshake, int bufferoffset, uint len) { uint offset = 0; bufferoffset += 772; //assert(12 <= len); offset += handshake[bufferoffset]; bufferoffset++; offset += handshake[bufferoffset]; bufferoffset++; offset += handshake[bufferoffset]; bufferoffset++; offset += handshake[bufferoffset];// (*ptr); uint res = (offset % 728) + 776; if (res + 32 > 1535) { string msg = string.Format("[CDR.LibRTMP.RTMPHelper] Couldn't calculate correct digest offset (got {0}), exiting", res); LibRTMPLogger.Log(LibRTMPLogLevel.Warning, msg); throw new Exception(msg); } return(res); }
public static uint GetDigestOffset1(byte[] handshake, int bufferoffset, uint len) { int offset = 0; bufferoffset += 8; offset += handshake[bufferoffset]; bufferoffset++; offset += handshake[bufferoffset]; bufferoffset++; offset += handshake[bufferoffset]; bufferoffset++; offset += handshake[bufferoffset]; int res = (offset % 728) + 12; if (res + 32 > 771) { string msg = string.Format("[CDR.LibRTMP.RTMPHelper] Couldn't calculate digest offset (got {0}), exiting!", res); LibRTMPLogger.Log(LibRTMPLogLevel.Warning, msg); throw new Exception(msg); } return((uint)res); }
public static uint GetDHOffset1(byte[] handshake, int bufferoffset, uint len) { int offset = 0; bufferoffset += 1532; offset += handshake[bufferoffset]; bufferoffset++; offset += handshake[bufferoffset]; bufferoffset++; offset += handshake[bufferoffset]; bufferoffset++; offset += handshake[bufferoffset];// (*ptr); int res = (offset % 632) + 772; if (res + 128 > 1531) { string msg = string.Format("[CDR.LibRTMP.RTMPHelper] Couldn't calculate DH offset (got {0}), exiting!", res); LibRTMPLogger.Log(LibRTMPLogLevel.Warning, msg); throw new Exception(msg); } return((uint)res); }
/// <summary> /// Check is the key is valid see RFC 2631, Section 2.1.5, http://www.ietf.org/rfc/rfc2631.txt /// </summary> public static bool IsValidPublicKey(Org.BouncyCastle.Math.BigInteger y, Org.BouncyCastle.Math.BigInteger p, Org.BouncyCastle.Math.BigInteger q) { Org.BouncyCastle.Math.BigInteger bn; // y must lie in [2,p-1] // check y < 2 then failed bn = new Org.BouncyCastle.Math.BigInteger("2"); if (y.CompareTo(bn) < 0) { LibRTMPLogger.Log(LibRTMPLogLevel.Warning, "[CDR.LibRTMP.RTMPHelper.IsValidPublicKey] DH public key must be at least 2"); return(false); } // y must lie in [2,p-1] bn = new Org.BouncyCastle.Math.BigInteger(p.ToString()); bn = bn.Subtract(new Org.BouncyCastle.Math.BigInteger("1")); if (y.CompareTo(bn) > 0) { LibRTMPLogger.Log(LibRTMPLogLevel.Warning, "[CDR.LibRTMP.RTMPHelper.IsValidPublicKey] DH public key must be at most p-2"); return(false); } // Verify with Sophie-Germain prime // // This is a nice test to make sure the public key position is calculated // correctly. This test will fail in about 50% of the cases if applied to // random data. bn = y.ModPow(q, p); if (bn.CompareTo(new Org.BouncyCastle.Math.BigInteger("1")) != 0) { LibRTMPLogger.Log(LibRTMPLogLevel.Warning, "[CDR.LibRTMP.RTMPHelper.IsValidPublicKey] DH public key does not fulfill y^q mod p = 1"); return(false); } return(true); }
public void Encode(List <byte> output) { if (type == AMFDataType.AMF_INVALID) { return; } switch (type) { case AMFDataType.AMF_NUMBER: if (string.IsNullOrEmpty(stringName)) { RTMPHelper.EncodeNumber(output, NumberValue); } else { RTMPHelper.EncodeNumber(output, stringName, NumberValue); } break; case AMFDataType.AMF_BOOLEAN: if (string.IsNullOrEmpty(stringName)) { RTMPHelper.EncodeBoolean(output, BooleanValue); } else { RTMPHelper.EncodeBoolean(output, stringName, BooleanValue); } break; case AMFDataType.AMF_STRING: if (string.IsNullOrEmpty(stringName)) { RTMPHelper.EncodeString(output, StringValue); } else { RTMPHelper.EncodeString(output, stringName, StringValue); } break; case AMFDataType.AMF_NULL: output.Add(0x05); break; case AMFDataType.AMF_OBJECT: if (!string.IsNullOrEmpty(stringName)) { short length = System.Net.IPAddress.HostToNetworkOrder((short)stringName.Length); output.AddRange(BitConverter.GetBytes(length)); output.AddRange(Encoding.ASCII.GetBytes(stringName)); } objVal.Encode(output); break; default: LibRTMPLogger.Log(LibRTMPLogLevel.Trace, string.Format("AMFObjectProperty.Encode invalid type: {0}", type)); break; } //switch }
public int Decode(byte[] buffer, int bufferOffset, int size, bool bDecodeName) { int originalSize = size; if (size == 0 || buffer == null) { return(-1); } if (buffer[bufferOffset] == 0x05) { type = AMFDataType.AMF_NULL; return(1); } if (bDecodeName && size < 4) // at least name (length + at least 1 byte) and 1 byte of data { return(-1); } if (bDecodeName) { ushort nNameSize = RTMPHelper.ReadInt16(buffer, bufferOffset); if (nNameSize > size - (short)sizeof(short)) { return(-1); } stringName = RTMPHelper.ReadString(buffer, bufferOffset); size -= sizeof(short) + stringName.Length; bufferOffset += sizeof(short) + stringName.Length; } if (size == 0) { return(-1); } size--; int stringSize = 0; int result = 0; switch (buffer[bufferOffset]) { case (byte)AMFDataType.AMF_NUMBER: if (size < (int)sizeof(double)) { return(-1); } numVal = RTMPHelper.ReadNumber(buffer, bufferOffset + 1); size -= sizeof(double); type = AMFDataType.AMF_NUMBER; break; case (byte)AMFDataType.AMF_BOOLEAN: if (size < 1) { return(-1); } numVal = Convert.ToDouble(RTMPHelper.ReadBool(buffer, bufferOffset + 1)); size--; type = AMFDataType.AMF_BOOLEAN; break; case (byte)AMFDataType.AMF_STRING: stringSize = RTMPHelper.ReadInt16(buffer, bufferOffset + 1); if (size < stringSize + (int)sizeof(short)) { return(-1); } stringVal = RTMPHelper.ReadString(buffer, bufferOffset + 1); size -= sizeof(short) + stringSize; type = AMFDataType.AMF_STRING; break; case (byte)AMFDataType.AMF_OBJECT: objVal = new AMFObject(); result = objVal.Decode(buffer, bufferOffset + 1, size, true); if (result == -1) { return(-1); } size -= result; type = AMFDataType.AMF_OBJECT; break; case (byte)AMFDataType.AMF_MOVIECLIP: LibRTMPLogger.Log(LibRTMPLogLevel.Trace, "AMF_MOVIECLIP reserved!"); return(-1); case (byte)AMFDataType.AMF_NULL: case (byte)AMFDataType.AMF_UNDEFINED: case (byte)AMFDataType.AMF_UNSUPPORTED: type = AMFDataType.AMF_NULL; break; case (byte)AMFDataType.AMF_REFERENCE: LibRTMPLogger.Log(LibRTMPLogLevel.Trace, "AMF_REFERENCE not supported!"); return(-1); case (byte)AMFDataType.AMF_ECMA_ARRAY: size -= 4; // next comes the rest, mixed array has a final 0x000009 mark and names, so its an object objVal = new AMFObject(); result = objVal.Decode(buffer, bufferOffset + 5, size, true); if (result == -1) { return(-1); } size -= result; type = AMFDataType.AMF_OBJECT; break; case (byte)AMFDataType.AMF_OBJECT_END: return(-1); case (byte)AMFDataType.AMF_STRICT_ARRAY: int nArrayLen = RTMPHelper.ReadInt32(buffer, bufferOffset + 1); size -= 4; objVal = new AMFObject(); result = objVal.DecodeArray(buffer, bufferOffset + 5, size, nArrayLen, false); if (result == -1) { return(-1); } size -= result; type = AMFDataType.AMF_OBJECT; break; case (byte)AMFDataType.AMF_DATE: if (size < 10) { return(-1); } date = RTMPHelper.ReadNumber(buffer, bufferOffset + 1); dateUTCOffset = RTMPHelper.ReadInt16(buffer, bufferOffset + 9); size -= 10; break; case (byte)AMFDataType.AMF_LONG_STRING: stringSize = RTMPHelper.ReadInt32(buffer, bufferOffset + 1); if (size < stringSize + 4) { return(-1); } stringVal = RTMPHelper.ReadLongString(buffer, bufferOffset + 1); size -= (4 + stringSize); type = AMFDataType.AMF_STRING; break; case (byte)AMFDataType.AMF_RECORDSET: LibRTMPLogger.Log(LibRTMPLogLevel.Trace, "AMFObjectProperty.Decode AMF_RECORDSET reserved!"); return(-1); case (byte)AMFDataType.AMF_XML_DOC: LibRTMPLogger.Log(LibRTMPLogLevel.Trace, "AMFObjectProperty.Decode AMF_XML_DOC not supported!"); return(-1); case (byte)AMFDataType.AMF_TYPED_OBJECT: LibRTMPLogger.Log(LibRTMPLogLevel.Trace, "AMFObjectProperty.Decode AMF_TYPED_OBJECT not supported!"); return(-1); default: LibRTMPLogger.Log(LibRTMPLogLevel.Trace, string.Format("AMFObjectProperty.Decode Unknown datatype {0}", buffer[bufferOffset])); return(-1); } //switch return(originalSize - size); }
public void Dump() { LibRTMPLogger.Log(LibRTMPLogLevel.Trace, string.Format("[CDR.LibRTMP.RTMPPACKET] packet type: 0x%02x. channel: 0x%02x. info 1: %d info 2: %d. Body size: %lu. body: 0x%02x", packetType, channel, timeStamp, infoField2, bodySize, body != null ? body[0].ToString() : "0")); }