<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0"/>
<supportedRuntime version="v2.0.50727"/>
</startup>
</configuration>
OpenCV基础介绍
OpenCVSharp,一个对OpenCV 库的C#实现,可能是由于内容开始是网络地址(http://...)完整的英文词截取后不能换行造成 为避免代码造成手机端排版的混乱,可适当增加文字描述,将代码往后推移
https://github.com/shimat/opencvsharp
点击查看网友教程
资料1:官网OpenCvSharp的api(http://shimat.github.io/opencvsharp/api/OpenCvSharp.Cv2.html)
资料2:官方的openCvSharp的例子(https://github.com/shimat/opencvsharp_samples/)
资料3:C#opencv的例子(https://www.csharpcodi.com/csharp-examples/)
资料3的网站比较好用,哪个算子不会用,直接搜就行了,进去后根据例程学习一下就会了
编译OpenCVSharp的程序时候一定要制定目标平台式x86还是x64

OpenCVSharp使用
相较于SharperCV与OpenCVDotNet,OpenCvSharp直接封装了更多的OpenCV方法,降低学习难度

输入如下测试代码
using OpenCvSharp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace OpenCvSharp_Demo
{
internal class Program
{
static void Main(string[] args)
{
Mat mat = new Mat("test.jpg");
Cv2.ImShow("test.jpg", mat);
Cv2.WaitKey();
Cv2.DestroyAllWindows();
}
}
}
Golang、PHP、Java、C#、ObjectC互通DES加密与解密
在完成一个大项目时候,我们要用到多语言来开发接口,每个模块可能分配到各小组中,各小组成员用到语言往往不一样,在向接口传递参数的时候,就要用到加密与解密。
在网上找了一些,这篇文章中有通用的写法,《PHP、JAVA、C#、Object-C 通用的DES加密》。
我只对PHP和Golang加密与解密进行了修改,其它语言并没有修改!
PHP:
/**
* @desc DES加密码与解密
*/
class Des {
//密钥8位
public $key = '256&#@$M';
/**
* @desc 加密返回大写十六进制字符串
* @param string $str
* @return string
*/
public function encrypt($str) {
$size = mcrypt_get_block_size (MCRYPT_DES, MCRYPT_MODE_CBC);
$str = $this->pkcs5Pad($str, $size);
return strtoupper(bin2hex( mcrypt_encrypt(MCRYPT_DES, $this->key, $str, MCRYPT_MODE_CBC, $this->key)));
}
/**
* @desc 解密
* @param string $str
* @return string
*/
public function decrypt($str) {
$strBin = $this->hex2bin(strtolower($str));
$str = mcrypt_decrypt(MCRYPT_DES, $this->key, $strBin, MCRYPT_MODE_CBC, $this->key);
$str = $this->pkcs5Unpad($str);
return $str;
}
public function hex2bin($hexData) {
$binData = '';
for($i = 0; $i < strlen ($hexData ); $i += 2) {
$binData .= chr(hexdec(substr($hexData, $i, 2)));
}
return $binData;
}
public function pkcs5Pad($text, $blocksize) {
$pad = $blocksize - (strlen($text) % $blocksize);
return $text . str_repeat(chr($pad), $pad);
}
public function pkcs5Unpad($text) {
$pad = ord ($text{strlen($text) - 1});
if ($pad > strlen($text)) {
return false;
}
if (strspn($text, chr($pad), strlen($text) - $pad) != $pad) {
return false;
}
return substr($text, 0, -1 * $pad);
}
}
$obj = new DES();
echo '<pre>';
echo $str = $obj->encrypt('123456');
echo '<br/>========================================<br/>';
echo $obj->decrypt($str);
下面再介绍一下Golang的,这里有篇文章详细的介绍了《Go加密解密之AES》,并附有代码。
Golang:
package main
import (
"bytes"
"crypto/cipher"
"crypto/des"
"encoding/base64"
"fmt"
)
func main() {
// DES 加解密
testDes()
// 3DES加解密
test3Des()
}
func testDes() {
key := []byte("256&#@$M")
result, err := DesEncrypt([]byte("123456"), key)
if err != nil {
panic(err)
}
fmt.Println(base64.StdEncoding.EncodeToString(result))
hexstr := fmt.Sprintf("%X", result)
fmt.Println(hexstr)
origData, err := DesDecrypt(result, key)
if err != nil {
panic(err)
}
fmt.Println("=======")
fmt.Println(string(origData))
}
func test3Des() {
key := []byte("256&#@$Msefiel#fi32lf3e!")
result, err := TripleDesEncrypt([]byte("123456"), key)
if err != nil {
panic(err)
}
fmt.Println(base64.StdEncoding.EncodeToString(result))
origData, err := TripleDesDecrypt(result, key)
if err != nil {
panic(err)
}
fmt.Println(string(origData))
}
func DesEncrypt(origData, key []byte) ([]byte, error) {
block, err := des.NewCipher(key)
if err != nil {
return nil, err
}
origData = PKCS5Padding(origData, block.BlockSize())
// origData = ZeroPadding(origData, block.BlockSize())
blockMode := cipher.NewCBCEncrypter(block, key)
crypted := make([]byte, len(origData))
// 根据CryptBlocks方法的说明,如下方式初始化crypted也可以
// crypted := origData
blockMode.CryptBlocks(crypted, origData)
return crypted, nil
}
func DesDecrypt(crypted, key []byte) ([]byte, error) {
block, err := des.NewCipher(key)
if err != nil {
return nil, err
}
blockMode := cipher.NewCBCDecrypter(block, key)
origData := make([]byte, len(crypted))
// origData := crypted
blockMode.CryptBlocks(origData, crypted)
origData = PKCS5UnPadding(origData)
// origData = ZeroUnPadding(origData)
return origData, nil
}
// 3DES加密
func TripleDesEncrypt(origData, key []byte) ([]byte, error) {
block, err := des.NewTripleDESCipher(key)
if err != nil {
return nil, err
}
origData = PKCS5Padding(origData, block.BlockSize())
// origData = ZeroPadding(origData, block.BlockSize())
blockMode := cipher.NewCBCEncrypter(block, key[:8])
crypted := make([]byte, len(origData))
blockMode.CryptBlocks(crypted, origData)
return crypted, nil
}
// 3DES解密
func TripleDesDecrypt(crypted, key []byte) ([]byte, error) {
block, err := des.NewTripleDESCipher(key)
if err != nil {
return nil, err
}
blockMode := cipher.NewCBCDecrypter(block, key[:8])
origData := make([]byte, len(crypted))
// origData := crypted
blockMode.CryptBlocks(origData, crypted)
origData = PKCS5UnPadding(origData)
// origData = ZeroUnPadding(origData)
return origData, nil
}
func ZeroPadding(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext)%blockSize
padtext := bytes.Repeat([]byte{0}, padding)
return append(ciphertext, padtext...)
}
func ZeroUnPadding(origData []byte) []byte {
return bytes.TrimRightFunc(origData, func(r rune) bool {
return r == rune(0)
})
}
func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}
func PKCS5UnPadding(origData []byte) []byte {
length := len(origData)
// 去掉最后一个字节 unpadding 次
unpadding := int(origData[length-1])
return origData[:(length - unpadding)]
}
其它几个版本的可以看一下《PHP、JAVA、C#、Object-C 通用的DES加密》
这里也顺便Copy一下过来~
C#:
public class MyDes
{
/// <summary>
/// DES加密方法
/// </summary>
/// <param name="strPlain">明文</param>
/// <param name="strDESKey">密钥</param>
/// <param name="strDESIV">向量</param>
/// <returns>密文</returns>
public static string Encode(string source, string _DESKey)
{
StringBuilder sb = new StringBuilder();
using (DESCryptoServiceProvider des = new DESCryptoServiceProvider())
{
byte[] key = ASCIIEncoding.ASCII.GetBytes(_DESKey);
byte[] iv = ASCIIEncoding.ASCII.GetBytes(_DESKey);
byte[] dataByteArray = Encoding.UTF8.GetBytes(source);
des.Mode = System.Security.Cryptography.CipherMode.CBC;
des.Key = key;
des.IV = iv;
string encrypt = "";
using (MemoryStream ms = new MemoryStream())
using (CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(dataByteArray, 0, dataByteArray.Length);
cs.FlushFinalBlock();
encrypt = Convert.ToBase64String(ms.ToArray());
}
return encrypt;
}
}
/// <summary>
/// 进行DES解密。
/// </summary>
/// <param name="pToDecrypt">要解密的base64串</param>
/// <param name="sKey">密钥,且必须为8位。</param>
/// <returns>已解密的字符串。</returns>
public static string Decode(string source, string sKey)
{
byte[] inputByteArray = System.Convert.FromBase64String(source);//Encoding.UTF8.GetBytes(source);
using (DESCryptoServiceProvider des = new DESCryptoServiceProvider())
{
des.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
des.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
System.IO.MemoryStream ms = new System.IO.MemoryStream();
using (CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(inputByteArray, 0, inputByteArray.Length);
cs.FlushFinalBlock();
cs.Close();
}
string str = Encoding.UTF8.GetString(ms.ToArray());
ms.Close();
return str;
}
}
}
Object C:
/*** JoDes.h ***/
#import <Foundation/Foundation.h>
#import <CommonCrypto/CommonDigest.h>
#import <CommonCrypto/CommonCryptor.h>
@interface JoDes : NSObject
+ (NSString *) encode:(NSString *)str key:(NSString *)key;
+ (NSString *) decode:(NSString *)str key:(NSString *)key;
@end
/*** JoDes.m ***/
//
// XLEncrytHelper.m
// NewHoldGold
//
// Created by 梁鑫磊 on 13-12-27.
// Copyright (c) 2013年 zsgjs. All rights reserved.
//
#import "JoDes.h"
@interface JoDes()
+ (NSString *) encodeBase64WithString:(NSString *)strData;
+ (NSString *) encodeBase64WithData:(NSData *)objData;
+ (NSData *) decodeBase64WithString:(NSString *)strBase64;
+ (NSString *)doCipher:(NSString *)sTextIn key:(NSString *)sKey
context:(CCOperation)encryptOrDecrypt;
@end
@implementation JoDes
+ (NSString *) encode:(NSString *)str key:(NSString *)key
{
// doCipher 不能编汉字,所以要进行 url encode
NSMutableString* str1 = [JoDes urlEncode:str];
NSMutableString* encode = [NSMutableString stringWithString:[JoDes doCipher:str1 key:key context:kCCEncrypt]];
[JoDes formatSpecialCharacters:encode];
return encode;
}
+ (NSString *) decode:(NSString *)str key:(NSString *)key
{
NSMutableString *str1 = [NSMutableString stringWithString:str];
[JoDes reformatSpecialCharacters:str1];
NSString *rt = [JoDes doCipher:str1 key:key context:kCCDecrypt];
return rt;
}
+ (NSMutableString *)urlEncode:(NSString*)str
{
NSMutableString* encodeStr = [NSMutableString stringWithString:[str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
[encodeStr replaceOccurrencesOfString:@"+" withString:@"%2B" options:NSWidthInsensitiveSearch range:NSMakeRange(0, [encodeStr length])];
[encodeStr replaceOccurrencesOfString:@"/" withString:@"%2F" options:NSWidthInsensitiveSearch range:NSMakeRange(0, [encodeStr length])];
return encodeStr;
}
+ (void)formatSpecialCharacters:(NSMutableString *)str
{
[str replaceOccurrencesOfString:@"+" withString:@"$$" options:NSWidthInsensitiveSearch range:NSMakeRange(0, [str length])];
[str replaceOccurrencesOfString:@"/" withString:@"@@" options:NSWidthInsensitiveSearch range:NSMakeRange(0, [str length])];
}
+ (void)reformatSpecialCharacters:(NSMutableString *)str
{
[str replaceOccurrencesOfString:@"$$" withString:@"+" options:NSWidthInsensitiveSearch range:NSMakeRange(0, [str length])];
[str replaceOccurrencesOfString:@"@@" withString:@"/" options:NSWidthInsensitiveSearch range:NSMakeRange(0, [str length])];
}
+ (NSString *)encodeBase64WithString:(NSString *)strData {
return [JoDes encodeBase64WithData:[strData dataUsingEncoding:NSUTF8StringEncoding]];
}
+ (NSString *)encodeBase64WithData:(NSData *)objData {
NSString *encoding = nil;
unsigned char *encodingBytes = NULL;
@try {
static char encodingTable[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static NSUInteger paddingTable[] = {0,2,1};
NSUInteger dataLength = [objData length];
NSUInteger encodedBlocks = (dataLength * 8) / 24;
NSUInteger padding = paddingTable[dataLength % 3];
if( padding > 0 ) encodedBlocks++;
NSUInteger encodedLength = encodedBlocks * 4;
encodingBytes = malloc(encodedLength);
if( encodingBytes != NULL ) {
NSUInteger rawBytesToProcess = dataLength;
NSUInteger rawBaseIndex = 0;
NSUInteger encodingBaseIndex = 0;
unsigned char *rawBytes = (unsigned char *)[objData bytes];
unsigned char rawByte1, rawByte2, rawByte3;
while( rawBytesToProcess >= 3 ) {
rawByte1 = rawBytes[rawBaseIndex];
rawByte2 = rawBytes[rawBaseIndex+1];
rawByte3 = rawBytes[rawBaseIndex+2];
encodingBytes[encodingBaseIndex] = encodingTable[((rawByte1 >> 2) & 0x3F)];
encodingBytes[encodingBaseIndex+1] = encodingTable[((rawByte1 << 4) & 0x30) | ((rawByte2 >> 4) & 0x0F) ];
encodingBytes[encodingBaseIndex+2] = encodingTable[((rawByte2 << 2) & 0x3C) | ((rawByte3 >> 6) & 0x03) ];
encodingBytes[encodingBaseIndex+3] = encodingTable[(rawByte3 & 0x3F)];
rawBaseIndex += 3;
encodingBaseIndex += 4;
rawBytesToProcess -= 3;
}
rawByte2 = 0;
switch (dataLength-rawBaseIndex) {
case 2:
rawByte2 = rawBytes[rawBaseIndex+1];
case 1:
rawByte1 = rawBytes[rawBaseIndex];
encodingBytes[encodingBaseIndex] = encodingTable[((rawByte1 >> 2) & 0x3F)];
encodingBytes[encodingBaseIndex+1] = encodingTable[((rawByte1 << 4) & 0x30) | ((rawByte2 >> 4) & 0x0F) ];
encodingBytes[encodingBaseIndex+2] = encodingTable[((rawByte2 << 2) & 0x3C) ];
// we can skip rawByte3 since we have a partial block it would always be 0
break;
}
// compute location from where to begin inserting padding, it may overwrite some bytes from the partial block encoding
// if their value was 0 (cases 1-2).
encodingBaseIndex = encodedLength - padding;
while( padding-- > 0 ) {
encodingBytes[encodingBaseIndex++] = '=';
}
encoding = [[NSString alloc] initWithBytes:encodingBytes length:encodedLength encoding:NSASCIIStringEncoding];
}
}
@catch (NSException *exception) {
encoding = nil;
NSLog(@"WARNING: error occured while tring to encode base 32 data: %@", exception);
}
@finally {
if( encodingBytes != NULL ) {
free( encodingBytes );
}
}
return encoding;
}
+ (NSData *)decodeBase64WithString:(NSString *)strBase64 {
NSData *data = nil;
unsigned char *decodedBytes = NULL;
@try {
#define __ 255
static char decodingTable[256] = {
__,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0x00 - 0x0F
__,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0x10 - 0x1F
__,__,__,__, __,__,__,__, __,__,__,62, __,__,__,63, // 0x20 - 0x2F
52,53,54,55, 56,57,58,59, 60,61,__,__, __, 0,__,__, // 0x30 - 0x3F
__, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, // 0x40 - 0x4F
15,16,17,18, 19,20,21,22, 23,24,25,__, __,__,__,__, // 0x50 - 0x5F
__,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, // 0x60 - 0x6F
41,42,43,44, 45,46,47,48, 49,50,51,__, __,__,__,__, // 0x70 - 0x7F
__,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0x80 - 0x8F
__,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0x90 - 0x9F
__,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0xA0 - 0xAF
__,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0xB0 - 0xBF
__,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0xC0 - 0xCF
__,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0xD0 - 0xDF
__,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0xE0 - 0xEF
__,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0xF0 - 0xFF
};
strBase64 = [strBase64 stringByReplacingOccurrencesOfString:@"=" withString:@""];
NSData *encodedData = [strBase64 dataUsingEncoding:NSASCIIStringEncoding];
unsigned char *encodedBytes = (unsigned char *)[encodedData bytes];
NSUInteger encodedLength = [encodedData length];
NSUInteger encodedBlocks = (encodedLength+3) >> 2;
NSUInteger expectedDataLength = encodedBlocks * 3;
unsigned char decodingBlock[4];
decodedBytes = malloc(expectedDataLength);
if( decodedBytes != NULL ) {
NSUInteger i = 0;
NSUInteger j = 0;
NSUInteger k = 0;
unsigned char c;
while( i < encodedLength ) {
c = decodingTable[encodedBytes[i]];
i++;
if( c != __ ) {
decodingBlock[j] = c;
j++;
if( j == 4 ) {
decodedBytes[k] = (decodingBlock[0] << 2) | (decodingBlock[1] >> 4);
decodedBytes[k+1] = (decodingBlock[1] << 4) | (decodingBlock[2] >> 2);
decodedBytes[k+2] = (decodingBlock[2] << 6) | (decodingBlock[3]);
j = 0;
k += 3;
}
}
}
// Process left over bytes, if any
if( j == 3 ) {
decodedBytes[k] = (decodingBlock[0] << 2) | (decodingBlock[1] >> 4);
decodedBytes[k+1] = (decodingBlock[1] << 4) | (decodingBlock[2] >> 2);
k += 2;
} else if( j == 2 ) {
decodedBytes[k] = (decodingBlock[0] << 2) | (decodingBlock[1] >> 4);
k += 1;
}
data = [[NSData alloc] initWithBytes:decodedBytes length:k];
}
}
@catch (NSException *exception) {
data = nil;
NSLog(@"WARNING: error occured while decoding base 32 string: %@", exception);
}
@finally {
if( decodedBytes != NULL ) {
free( decodedBytes );
}
}
return data;
}
+ (NSString *)doCipher:(NSString *)sTextIn key:(NSString *)sKey
context:(CCOperation)encryptOrDecrypt {
NSStringEncoding EnC = NSUTF8StringEncoding;
NSMutableData *dTextIn;
if (encryptOrDecrypt == kCCDecrypt) {
dTextIn = [[JoDes decodeBase64WithString:sTextIn] mutableCopy];
}
else{
dTextIn = [[sTextIn dataUsingEncoding: EnC] mutableCopy];
}
NSMutableData * dKey = [[sKey dataUsingEncoding:EnC] mutableCopy];
[dKey setLength:kCCBlockSizeDES];
uint8_t *bufferPtr1 = NULL;
size_t bufferPtrSize1 = 0;
size_t movedBytes1 = 0;
//uint8_t iv[kCCBlockSizeDES];
//memset((void *) iv, 0x0, (size_t) sizeof(iv));
// Byte iv[] = {0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF};
bufferPtrSize1 = ([sTextIn length] + kCCKeySizeDES) & ~(kCCKeySizeDES -1);
bufferPtr1 = malloc(bufferPtrSize1 * sizeof(uint8_t));
memset((void *)bufferPtr1, 0x00, bufferPtrSize1);
CCCrypt(encryptOrDecrypt, // CCOperation op
kCCAlgorithmDES, // CCAlgorithm alg
kCCOptionPKCS7Padding, // CCOptions options
[dKey bytes], // const void *key
[dKey length], // size_t keyLength //
[dKey bytes], // const void *iv
[dTextIn bytes], // const void *dataIn
[dTextIn length], // size_t dataInLength
(void *)bufferPtr1, // void *dataOut
bufferPtrSize1, // size_t dataOutAvailable
&movedBytes1);
//[dTextIn release];
//[dKey release];
NSString * sResult;
if (encryptOrDecrypt == kCCDecrypt){
sResult = [[NSString alloc] initWithData:[NSData dataWithBytes:bufferPtr1 length:movedBytes1] encoding:EnC];
free(bufferPtr1);
}
else {
NSData *dResult = [NSData dataWithBytes:bufferPtr1 length:movedBytes1];
free(bufferPtr1);
sResult = [JoDes encodeBase64WithData:dResult];
}
return sResult;
}
Java:
package com.example.aric.test;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import android.util.Base64;
public class DES {
public final static String DES_KEY_STRING = "ABSujsuu";
public static String encrypt(String message, String key) throws Exception {
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
DESKeySpec desKeySpec = new DESKeySpec(key.getBytes("UTF-8"));
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
IvParameterSpec iv = new IvParameterSpec(key.getBytes("UTF-8"));
cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
return encodeBase64(cipher.doFinal(message.getBytes("UTF-8")));
}
public static String decrypt(String message, String key) throws Exception {
byte[] bytesrc = decodeBase64(message);//convertHexString(message);
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
DESKeySpec desKeySpec = new DESKeySpec(key.getBytes("UTF-8"));
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
IvParameterSpec iv = new IvParameterSpec(key.getBytes("UTF-8"));
cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
byte[] retByte = cipher.doFinal(bytesrc);
return new String(retByte);
}
public static byte[] convertHexString(String ss) {
byte digest[] = new byte[ss.length() / 2];
for (int i = 0; i < digest.length; i++) {
String byteString = ss.substring(2 * i, 2 * i + 2);
int byteValue = Integer.parseInt(byteString, 16);
digest[i] = (byte) byteValue;
}
return digest;
}
public static String toHexString(byte b[]) {
StringBuffer hexString = new StringBuffer();
for (int i = 0; i < b.length; i++) {
String plainText = Integer.toHexString(0xff & b[i]);
if (plainText.length() < 2)
plainText = "0" + plainText;
hexString.append(plainText);
}
return hexString.toString();
}
public static String encodeBase64(byte[] b) {
return Base64.encodeToString(b, Base64.DEFAULT);
}
public static byte[] decodeBase64(String base64String) {
return Base64.decode(base64String, Base64.DEFAULT);
}
}
1、下载
从如下地址下载mycat的安装包:
https://github.com/MyCATApache/Mycat-download
eg:Mycat-server-1.6.6.1-release-20181031195535-win.tar.gz
2、解压
解压下载的安装包
3、安装
安装mycat前需要先安装jdk和mysql。mycat1.6版本建议使用的jdk是1.7以上版本,mysql建议使用5.6版本。
安装完jdk和mysql后,进入mycat解压目录下的bin目录,如本文的路径如下:
D:\dev\mycat\bin
在打开的cmd命令行窗口中,执行如下命令安装mycat(注意需要管理员账户登录,如果不是请使用管理员身份运行cmd打开命令行窗口):
mycat.bat install
4、启动和停止
可以使用如下命令启动mycat服务
mycat.bat start
启动后可以通过如下命令查看mycat的运行状态:
mycat.bat status
可以使用如下命令停止mycat服务
mycat.bat stop
5、mycat配置
5.1、schema.xml配置文件——修改mycat与mysql的链接信息
我们打开mycat安装目录,并进入conf目录,打开schema.xml配置文件,schema.xml配置文件是mycat中重要的配置文件之一,它涵盖了mycat的逻辑库、表、分片规则、分批按节点及数据源。这里我们对默认的schema.xml进行简单的修改配置(注意备份一个原始的配置文件),主要配置本机的mysql链接信息。找到dataHost节点,按照当前自己mysql的配置信息来修改配置。如下为我修改后的该部分配置:
<?xml version="1.0"?><!DOCTYPE mycat:schema SYSTEM "schema.dtd"><mycat:schema xmlns:mycat="http://io.mycat/">
<!-- 定义一个MyCat的模式,此处定义了一个逻辑数据库名称TestDB -->
<!-- “checkSQLschema”:描述的是当前的连接是否需要检测数据库的模式 -->
<!-- “sqlMaxLimit”:表示返回的最大的数据量的行数 -->
<!-- “dataNode="dn1"”:该操作使用的数据节点是dn1的逻辑名称 -->
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1"/>
<!-- 定义个数据的操作节点,以后这个节点会进行一些库表分离使用 -->
<!-- “dataHost="localhost1"”:定义数据节点的逻辑名称 -->
<!-- “database="mldn"”:定义数据节点要使用的数据库名称 -->
<dataNode name="dn1" dataHost="localhost1" database="mydb" />
<!-- 定义数据节点,包括各种逻辑项的配置 -->
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<!-- 配置真实MySQL与MyCat的心跳 -->
<heartbeat>select user()</heartbeat>
<!-- 配置真实的MySQL的连接信息 -->
<writeHost host="hostM1" url="localhost:3306" user="root" password="123456"></writeHost>
</dataHost></mycat:schema>
这里面,有两个参数需要注意,balance和 switchType。
其中,balance指的负载均衡类型,目前的取值有4种:
1. balance="0", 不开启读写分离机制,所有读操作都发送到当前可用的writeHost上。
2. balance="1",全部的readHost与stand by writeHost参与select语句的负载均衡,简单的说,当双主双从模式(M1->S1,M2->S2,并且M1与 M2互为主备),正常情况下,M2,S1,S2都参与select语句的负载均衡。
3. balance="2",所有读操作都随机的在writeHost、readhost上分发。
4. balance="3",所有读请求随机的分发到wiriterHost对应的readhost执行,writerHost不负担读压力
switchType指的是切换的模式,目前的取值也有4种:
1. switchType='-1' 表示不自动切换
2. switchType='1' 默认值,表示自动切换
3. switchType='2' 基于MySQL主从同步的状态决定是否切换,心跳语句为 show slave status
4. switchType='3'基于MySQL galary cluster的切换机制(适合集群)(1.4.1),心跳语句为 show status like 'wsrep%'。
5.2、server.xml文件——配置mycat用户信息
<?xml version="1.0" encoding="UTF-8"?><!-- - - Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License. - You
may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0
- - Unless required by applicable law or agreed to in writing, software -
distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the
License for the specific language governing permissions and - limitations
under the License. --><!DOCTYPE mycat:server SYSTEM "server.dtd"><mycat:server xmlns:mycat="http://io.mycat/">
<system>
<property name="nonePasswordLogin">0</property> <!-- 0为需要密码登陆、1为不需要密码登陆 ,默认为0,设置为1则需要指定默认账户-->
<property name="useHandshakeV10">1</property>
<property name="useSqlStat">0</property> <!-- 1为开启实时统计、0为关闭 -->
<property name="useGlobleTableCheck">0</property> <!-- 1为开启全加班一致性检测、0为关闭 -->
<property name="sequnceHandlerType">2</property>
<property name="subqueryRelationshipCheck">false</property> <!-- 子查询中存在关联查询的情况下,检查关联字段中是否有分片字段 .默认 false -->
<!-- <property name="useCompression">1</property>--> <!--1为开启mysql压缩协议-->
<!-- <property name="fakeMySQLVersion">5.6.20</property>--> <!--设置模拟的MySQL版本号-->
<!-- <property name="processorBufferChunk">40960</property> -->
<!--
<property name="processors">1</property>
<property name="processorExecutor">32</property>
-->
<!--默认为type 0: DirectByteBufferPool | type 1 ByteBufferArena | type 2 NettyBufferPool -->
<property name="processorBufferPoolType">0</property>
<!--默认是65535 64K 用于sql解析时最大文本长度 -->
<!--<property name="maxStringLiteralLength">65535</property>-->
<!--<property name="sequnceHandlerType">0</property>-->
<!--<property name="backSocketNoDelay">1</property>-->
<!--<property name="frontSocketNoDelay">1</property>-->
<!--<property name="processorExecutor">16</property>-->
<!--
<property name="serverPort">8066</property> <property name="managerPort">9066</property>
<property name="idleTimeout">300000</property> <property name="bindIp">0.0.0.0</property>
<property name="frontWriteQueueSize">4096</property> <property name="processors">32</property> -->
<!--分布式事务开关,0为不过滤分布式事务,1为过滤分布式事务(如果分布式事务内只涉及全局表,则不过滤),2为不过滤分布式事务,但是记录分布式事务日志-->
<property name="handleDistributedTransactions">0</property>
<!--
off heap for merge/order/group/limit 1开启 0关闭 -->
<property name="useOffHeapForMerge">1</property>
<!--
单位为m -->
<property name="memoryPageSize">64k</property>
<!--
单位为k -->
<property name="spillsFileBufferSize">1k</property>
<property name="useStreamOutput">0</property>
<!--
单位为m -->
<property name="systemReserveMemorySize">384m</property>
<!--是否采用zookeeper协调切换 -->
<property name="useZKSwitch">false</property>
<!-- XA Recovery Log日志路径 -->
<!--<property name="XARecoveryLogBaseDir">./</property>-->
<!-- XA Recovery Log日志名称 -->
<!--<property name="XARecoveryLogBaseName">tmlog</property>-->
<!--如果为 true的话 严格遵守隔离级别,不会在仅仅只有select语句的时候在事务中切换连接-->
<property name="strictTxIsolation">false</property>
<property name="useZKSwitch">true</property>
</system>
<!-- 全局SQL防火墙设置 -->
<!--白名单可以使用通配符%或着*-->
<!--例如<host host="127.0.0.*" user="root"/>-->
<!--例如<host host="127.0.*" user="root"/>-->
<!--例如<host host="127.*" user="root"/>-->
<!--例如<host host="1*7.*" user="root"/>-->
<!--这些配置情况下对于127.0.0.1都能以root账户登录-->
<!--
<firewall>
<whitehost>
<host host="1*7.0.0.*" user="root"/>
</whitehost>
<blacklist check="false">
</blacklist>
</firewall> -->
<!-- 定于mycat用户:root/123456 --> <user name="root" defaultAccount="true">
<property name="password">123456</property>
<!-- schema.xml指定逻辑数据库名称TESTDB -->
<property name="schemas">TESTDB</property>
<!-- 表级 DML 权限设置 -->
<!--
<privileges check="false">
<schema name="TESTDB" dml="0110" >
<table name="tb01" dml="0000"></table>
<table name="tb02" dml="1111"></table>
</schema>
</privileges>
-->
</user>
<!-- 定于mycat用户,只读:user/user --> <user name="user">
<property name="password">user</property>
<property name="schemas">TESTDB</property>
<property name="readOnly">true</property>
</user></mycat:server>
6、启动
6.1、启动方法一

找到mycat解压目录下的bin目录,bin目录下有一个叫startup_nowrap.bat的文件,这就是mycat的启动文件。
6.2、启动方法二

如果报错的话,可以在如下目录查看日志信息。
D:\dev\mycat\logs\mycat.log
7、测试
启动成功后,使用navicat连接mycat,新建一个mysql连接,如下图:连接成功,其中8066端口是mycat的默认端口

D:\dev\mycat\logs\switch.log查看读写分离是否配置成功。
2019-07-18 15:24:02: [dataHost=localhost1, dataSource=hostS1,statue=ok status -> error status] #从机启动失败,从机用不了会走主机不影响查询
2019-07-18 15:27:01: [dataHost=localhost1, dataSource=hostS1,statue=error status -> ok status] #读写分离配置成功
使用C#连接 MyCat 链接串
这里其实mycat和mysql没啥区别从我们程序的角度来看,一定要理解这句话啊,从程序的角度,最原始的方式就是通过Oracle提供的mysql.data.dll去连接,连接字符串
"server=127.0.0.1,8066;database=TESTDB;uid=root;pwd=123456;Pooling=true;Connection Lifetime=120;Connection Timeout=120;" 不知道为什么这么写就是提示找不到host,
改成这样:
"server=127.0.0.1;database=TESTDB;uid=root;pwd=123456;Pooling=true;Connection Lifetime=120;Connection Timeout=120;Port=8066"
就可以了。
下载地址:https://github.com/MyCATApache/Mycat-download

C#,.NET,MVC,处理blob视频的播放
C#,.NET,MVC,处理blob视频的播放
现在许多视频在线观看网站,你如果打开chrome查看其video标签,会发现它的src是一个以blob:开头的地址。可以看到他这里引入的并不是一个在线的视频存放地址,这样你通过爬虫脚本也无法下载该视频文件,通过一个new tab打开也于事无补,会提示你地址错误。
后端实现代码如下(示例):
//生成视图页面控制器
public ActionResult Index()
{
return View();
}
public void Video()
{
//这里需要获取全路径 如:D:\project\images\video\products\video.mp4
string filePath = this.Server.MapPath("~/images/video/products/video.mp4");
System.IO.FileInfo fileInfo = new System.IO.FileInfo(filePath);
if (fileInfo.Exists == true)
{
FileStream fs = new FileStream(filePath, FileMode.Open);
byte[] bytes = new byte[(int)fs.Length];
fs.Read(bytes, 0, bytes.Length);
fs.Close();
//Response.AddHeader("Content-Disposition", "attachment; filename=" + HttpUtility.UrlEncode(fileInfo.Name));
Response.AddHeader("Content-Length", "" + fileInfo.Length.ToString());
Response.AddHeader("Content-Transfer-Encoding", "binary");
Response.ContentType = "application/octet-stream";
Response.ContentEncoding = System.Text.Encoding.UTF8;
Response.BinaryWrite(bytes);
Response.Flush();
Response.End();
}
}
前端界面代码如下(示例):
<div>
<video id="video_player" width="660" height="364" controls="controls"></video>
</div>
<script>
//创建XMLHttpRequest对象
var xhr = new XMLHttpRequest();
//配置请求方式、请求地址以及是否同步
xhr.open('POST', '/AAAtest/Video', true);
//设置请求结果类型为blob
xhr.responseType = 'blob';
//请求成功回调函数
xhr.onload = function (e) {
if (this.status == 200) {//请求成功
//获取blob对象
var blob = this.response;
var video = document.getElementById('video_player');
//获取blob对象地址,并把值赋给容器
var obj_url = window.URL.createObjectURL(blob);
video.src = obj_url;
//video.play();
//setTimeout("revokeUrl('" + obj_url + "')", "2000"); //这里是在2秒后停止了播放
}
};
xhr.send();
function revokeUrl(url) {
window.URL.revokeObjectURL(url);
}
</script>
虚拟目录
创建虚拟目录vpath使用
string path=ctx.Server.MapPath("~/vpath");
path+="\\hello.txt";
File.WriteAllText(path,"hello world");
m_ReturnJson.bOK = true;
m_ReturnJson.sMsg = path;
访问:http://www.1xn1.com/vpath/hello.txt
要求说明:
通过网站上传文件保存到统一的文件服务器上。
服务器说明:
1.文件服务器以下称为FilesServer,IP地址为:192.168.1.213
2.Web服务器为以下称为WebServer,IP地址为:192.168.1.214
详细步骤:
(1)在FilesServer和WebServer上分别新建一个新用户,要求这两个用户的用户名和密码均相同,具体创建过程不再赘述。列如我创建的用户名是File_Share,密码为Share123
(2)在FilesServer上建立一个文件夹用来存储上传的文件,我这里新建了Share文件夹;然后将该文件夹设置为共享文件夹,具体步骤为(Windows Server 2012 Standard为例):
1)在Share文件加上右键——属性,选择共享选项卡,单击点共享按钮,在弹出的对话框中单击下拉列表,选择刚刚新建的File_Share用户。

2)根据自己的需要给File_Share用户添加读取/写入权限,然后单击共享按钮弹出对话框后点完成

3)返回Share属性对话框,单击高级共享--全限--添加--高级--立即查找

4)选中File_Share用户,单击确定,再单击确定来到以下的对话框,选中File_Share用户,根据需要加上完全控制等权限,然后确定。然后再两次一路确定,最终完成分享文件夹。

在WebServer的IIS的网站上右键--新建虚拟目录,别名随你喜欢,路径按照下图填,然后点击连接为,在连接为对话框中选特定用户,然后单击设置,填入File_Share的用户名和密码,然后一路确定。

回到IIS主界面,双击身份验证

选中匿名身份验证--编辑--设置填入File_Share的用户名和密码,一路确定。

如果是网站是.net版本,那么必须修改应用中的Web.config文件,<system.web>配置节中加入绿色部分<identity impersonate="true" ></identity>。
<system.web>
<identity impersonate="true" ></identity><!--加入这一部分-->
<compilation debug="true" targetFramework="4.5.2"/>
<httpRuntime targetFramework="4.5.2"/>
<httpModules>
<add name="ApplicationInsightsWebTracking" type="Microsoft.ApplicationInsights.Web.ApplicationInsightsHttpModule, Microsoft.AI.Web"/>
</httpModules>
</system.web>
NAS—IIS虚拟目录
之前项目中有上传图片视频等资源的功能,都是把资源上传到解决方案的目录下,如果越来越多占用的空间也越来越大,实在不可取。后来用到了NAS这样一个东西,一个网络存储器,感觉像一个云盘的实体。把所有的资源放在NAS中,方便很多。
1、NAS
NAS(Network Attached Storage)网络附属存储)按字面简单说就是连接在网络上,具备资料存储功能的装置,因此也称为"网络存储器"。它是一种专用数据存储服务器。它以数据为中心,将存储设备与服务器彻底分离,集中管理数据,从而释放带宽、提高性能、降低总拥有成本、保护投资。其成本远远低于使用服务器存储,而效率却远远高于后者。目前国际著名的NAS企业有Netapp、EMC、OUO等。
优点:
NAS 是一种采用直接与网络介质相连的特殊设备实现数据存储的机制。由于这些设备都分配有 IP 地址,所以客户机通过充当数据网关的服务器可以对其进行存取访问,甚至在某些情况下,不需要任何中间介质客户机也可以直接访问这些设备。
第一,NAS适用于那些需要通过网络将文件数据传送到多台客户机上的用户。NAS设备在数据必须长距离传送的环境中可以很好地发挥作用。
第二,NAS设备非常易于部署。可以使NAS主机、客户机和其他设备广泛分布在整个企业的网络环境中。NAS可以提供可靠的文件级数据整合,因为文件锁定是由设备自身来处理的。
第三,NAS应用于高效的文件共享任务中,例如UNIX中的NFS和Windows NT中的CIFS,其中基于网络的文件级锁定提供了高级并发访问保护的功能。
第四,NAS能够满足那些希望降低存储成本但又无法承受SAN昂贵价格的中小企业的需求,具有相当好的性能价格比。究竟哪些行业可以使用到NAS设备呢?首先,看这个单位的核心业务是否建立在某种信息系统上,对数据的安全性要求很高;其次,看该信息系统是否已经有或者将会有海量的数据需要保存,并且对数据管理程度要求较高;最后,还可以判断一下网络中是否有异构平台,或者以后会不会用到。如果上述有一个问题的答案是肯定的,那么就有必要重点考虑使用NAS设备。
2、使用
在同一局域网下,如果NAS的权限是everyone,其实和我们把自己电脑的分享文件共享一样,可以进入网络下访问NAS中的文件:

在代码中我们可以将资源的地址由来源的本地或服务器改为NAS的地址,将资源地址存入数据库中,如下:
<span style="font-size:18px;">string webpath = "\\\\WDMYCLOUD\\Public\\classStyle\\" + strName;</span>
资源存储好,当然也需要读取,显示在界面上。因为我们的资源都放在了网络存储器NAS上,我们本地浏览程序时,是访问不到资源的。需要把程序发布到IIS上,这时我们要做的就是,添加虚拟目录,将NAS上资源的目录添加到IIS中发布,如下:

设置好虚拟目录后,就可以成功将视频或图片等资源加载出来了,还是很方便的!
Winform窗口实现多显示屏显示的2种方法
一台主机连接了2台显示器(2个显卡),要求一个程序的两个窗体在不同的显示器上显示:显示器1 显示From1,显示器2 显示From2。代码及说明如下
Form1不需要变更代码,From2添加如下代码:
// 方法一:
From2 frm2 = new From2();
if (Screen.AllScreens.Count() != 1)
{
frm2.Left = Screen.AllScreens[0].Bounds.Width;
frm2.Top = 0;
frm2.Size = new System.Drawing.Size(Screen.AllScreens[1].Bounds.Width, Screen.AllScreens[1].Bounds.Height);
}
// 方法二:
this.Left = ((Screen.AllScreens[1].Bounds.Width - this.Width) / 2);
this.Top = ((Screen.AllScreens[1].Bounds.Height - this.Height) / 2);
this.Size = new System.Drawing.Size(Screen.AllScreens[1].Bounds.Width, Screen.AllScreens[1].Bounds.Height);
C# winform 双屏显示
双屏显示1
// 利用WinForm中的Screen类,即可比较方便地实现多窗体分别在多个屏幕上显示。
//?获取当前系统连接的屏幕数量: Screen.AllScreens.Count();
//?获取当前屏幕的名称:string CurrentScreenName = Screen.FromControl(this).DeviceName;
//?获取当前屏幕对象:Screen CurrentScreen = Screen.FromControl(this);
//?获取当前鼠标所在的屏幕:Screen CurrentScreen = Screen.FromPoint(new Point(Cursor.Position.X, Cursor.Position.Y));
//?让窗体在第2个屏幕上显示:
//this.Left = ((Screen.AllScreens[1].Bounds.Width - this.Width) / 2);
//this.Top = ((Screen.AllScreens[1].Bounds.Height - this.Height) / 2);
private void showOnMonitor(int showOnMonitor)
{
Screen[] sc;
sc = Screen.AllScreens;
if (showOnMonitor >= sc.Length)
{
showOnMonitor = 0;
}
this.FormBorderStyle = FormBorderStyle.None; //无边框全屏显示
this.StartPosition = FormStartPosition.Manual;
this.Location = new Point(sc[showOnMonitor].Bounds.Left, sc[showOnMonitor].Bounds.Top);
//this.Location = new Point(((sc[showOnMonitor].Bounds.Width-this.Width)/2), ((sc[showOnMonitor].Bounds.Height-this.Height)/2));
// If you intend the form to be maximized, change it to normal then maximized.
//this.WindowState = FormWindowState.Normal;
this.WindowState = FormWindowState.Maximized;//最大化窗口
}
如果接双显卡时showOnMonitor 参数等于0为主屏,1为扩展屏
双屏显示2
private void showOnMonitor2()
{
Screen[] sc;
sc = Screen.AllScreens;
//get all the screen width and heights
Form1 f = new Form1();
f.FormBorderStyle = FormBorderStyle.None;
f.Left = sc[1].Bounds.Width;
f.Top = sc[1].Bounds.Height;
f.StartPosition = FormStartPosition.Manual;
f.Location = sc[1].Bounds.Location;
Point p = new Point(sc[1].Bounds.Location.X, sc[1].Bounds.Location.Y);
f.Location = p;
f.WindowState = FormWindowState.Maximized;
f.Show();
}
接入双显卡时sc[0]为主屏、sc[1]扩展屏
一个窗体双屏显示
his.Location = new Point(0,0);
Screen[] sc;
sc = Screen.AllScreens;
this.Width = (sc[0].Bounds.Width + sc[1].Bounds.Width);//+20;
this.Height = (sc[0].Bounds.Height); //+200;
this.FormBorderStyle = FormBorderStyle.None; //边框样式
webBrowser1.Width = sc[0].Bounds.Width;
webBrowser1.Height = sc[0].Bounds.Height;
webBrowser1.Location = new Point(sc[0].Bounds.Location.X, sc[0].Bounds.Location.Y);
webBrowser1.Url = new Uri("http://www.google.com.hk");
webBrowser2.Width = sc[1].Bounds.Width;
webBrowser2.Height = sc[1].Bounds.Height;
webBrowser2.Location = new Point(sc[1].Bounds.Location.X, sc[1].Bounds.Location.Y);
webBrowser2.Url = new Uri("http://www.baidu.com");
C#设置双屏显示模式
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace RecordSystem.Common
{
public static class ScreenHelper
{
private const uint SDC_APPLY = 0x00000080;
private const uint SDC_TOPOLOGY_INTERNAL = 0x00000001;
private const uint SDC_TOPOLOGY_CLONE = 0x00000002;
/// <summary>
/// 扩展模式
/// </summary>
private const uint SDC_TOPOLOGY_EXTEND = 0x00000004;
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
private static extern long SetDisplayConfig(uint numPathArrayElements, IntPtr pathArray, uint numModeArrayElements,
IntPtr modeArray, uint flags);
/// <summary>
/// 设置屏幕的显示模式
/// </summary>
/// <param name="displayModel"></param>
/// <returns></returns>
private static bool SetScreen(uint displayModel)
{
return SetDisplayConfig(0, IntPtr.Zero, 0, IntPtr.Zero, SDC_APPLY | displayModel) == 0;
}
/// <summary>
/// 设置屏幕的显示模式
/// </summary>
/// <param name="type">模式(0 - 主屏 1 - 双屏复制 2 - 双屏扩展</param>
/// <returns></returns>
public static bool SetScreenMode(int type)
{
uint smode ;
switch (type)
{
case 0:
smode = SDC_APPLY | SDC_TOPOLOGY_INTERNAL ;
break;
case 1:
smode = SDC_APPLY | SDC_TOPOLOGY_CLONE ;
break;
case 2:
smode = SDC_APPLY | SDC_TOPOLOGY_EXTEND ;
break;
default :
smode = SDC_APPLY | SDC_TOPOLOGY_INTERNAL ;
break;
}
return SetDisplayConfig(0, IntPtr.Zero, 0, IntPtr.Zero, smode) == 0;
}
}
用C#破解Chrome浏览器cookie值
最近一个获取网站请求数据的需求,要求抓取网站某个页面请求的数据。使用Google Chrome浏览器查看了一下请求链接的传入参数,发现需要传入一个Token值才能获取数据。于是在Chrome中登录后,通过Postman请求成功,并将Token存储到了Cookie中。然而问题又来了,在代码层面如何获取这个Token呢?
解决方案
小编在网上查了一圈,发现Chrome浏览器的Cookie存储在本地的sqlite数据库中。在Chrome的安装目录中找到了sqlite的文件,通过读取sqlite数据库即可获得了Cookie值。如下图:

其中name是cookie的名称, encrypted_value字段是加密的cookie值,host_key就是站点域名了。但是这个Cookie值是加密的。
存储cookie目录:
C:\Users\用户名\AppData\Local\Google\Chrome\User Data\Default\Network\Cookies
各个版本的目录可能不同,有的在Local State文件夹下。
小编继续搜索,发现Chrome浏览器是开源的,算法是公开的,用到的加密算法是aes加密算法。我们不需要知道这个算法,只需要知道此算法需要一个秘钥,通过这个秘钥就可以进行加密和解密,代码如下。
实现代码
关键代码如下:
using (SqliteConnection connection = new SqliteConnection())
{
//1、获取google Chrome浏览器目录
var userprofilePath = Environment.GetEnvironmentVariable("USERPROFILE");
var sourceFile= $@"{userprofilePath}\AppData\Local\Google\Chrome\User Data\Default\Network\Cookies";
//var sourceFile = $@"{userprofilePath}\Desktop\11111111.txt";
var targetFile = $@"{Directory.GetCurrentDirectory()}\GoogleFile\Cookies";
//2、拷贝文件到本地目录,防止文件被占用
FileInfo file = new FileInfo(sourceFile);
if(!Directory.Exists($@"{Directory.GetCurrentDirectory()}\GoogleFile"))
Directory.CreateDirectory($@"{Directory.GetCurrentDirectory()}\GoogleFile");
if (file.Exists)
{
file.CopyTo(targetFile, true);
}
//3、链接sqlite数据库
connection.ConnectionString = $@"DataSource="+ targetFile;
connection.Open();
//4、通过select查询相关的语句
SqliteCommand command = new SqliteCommand("select host_key,name,encrypted_value from cookies where name='public-token' and host_key='.cponline.cnipa.gov.cn'", connection);
SqliteDataReader dataReader = command.ExecuteReader();
dataReader.Read();
byte[] encryptedValue = (byte[])dataReader["encrypted_value"];
//5、解密数据
int keyLength = 256 / 8;
int nonceLength = 96 / 8;
String kEncryptionVersionPrefix = "v10";
int GCM_TAG_LENGTH = 16;
//字符串内容取自C:\Users\用户名\AppData\Local\Google\Chrome\User Data\Local State文件的encrypted_key
byte[] encryptedKeyBytes = Convert.FromBase64String("RFBBUEkBAAAA0Iyd3wEV0RGMegDAT8KX6wEAAACVAmSA/y7+TLs+3WWdDv1ZAAAAAAIAAAAAABBmAAAAAQAAIAAAABV7dDMB8p+vKnLEjnrhnWB4DAbB/k5XAtjWGFnci/3qAAAAAA6AAAAAAgAAIAAAAH/pnc+fF6dhG8Fpw6yQezIXtMw48xNvuyRub/cZ62XaMAAAAP1pl5QqRJmd1J4V++dhE63MEA9F4NzCHb1aOMgTnFCo1+xSHYovSTzCoYFvoDfIFUAAAAAZzDzWwwpUm6yZG9tpYu/ioRSO8V16MetQy2s7L9HHO03Q6bO8Nr05Erl1QbjCVoSgSOU4krcerUsngMwIYFyb");
encryptedKeyBytes = encryptedKeyBytes.Skip("DPAPI".Length).Take(encryptedKeyBytes.Length - "DPAPI".Length).ToArray();
var keyBytes = System.Security.Cryptography.ProtectedData.Unprotect(encryptedKeyBytes, null, System.Security.Cryptography.DataProtectionScope.CurrentUser);
var nonce = encryptedValue.Skip(kEncryptionVersionPrefix.Length).Take(nonceLength).ToArray();
encryptedValue = encryptedValue.Skip(kEncryptionVersionPrefix.Length + nonceLength).Take(encryptedValue.Length - (kEncryptionVersionPrefix.Length + nonceLength)).ToArray();
var str = System.Web.HttpUtility.UrlDecode(AesGcmDecrypt(keyBytes, nonce, encryptedValue));
//6、获得值
Console.WriteLine($"{dataReader["host_key"]}-{dataReader["name"]}-{str}");
//7、关闭数据
connection.Close();
}
以上代码列出了解密步骤,大家可以根据自己的项目情况调整。
AesGcmDecrypt解密的方法:
public static string AesGcmDecrypt(byte[] keyBytes, byte[] nonce, byte[] encryptedValue)
{
GcmBlockCipher gcmBlockCipher = new GcmBlockCipher(new AesEngine());
AeadParameters aeadParameters = new AeadParameters(
new KeyParameter(keyBytes),
128,
nonce);
gcmBlockCipher.Init(false, aeadParameters);
byte[] plaintext = new byte[gcmBlockCipher.GetOutputSize(encryptedValue.Length)];
int length = gcmBlockCipher.ProcessBytes(encryptedValue, 0, encryptedValue.Length, plaintext, 0);
gcmBlockCipher.DoFinal(plaintext, length);
return Encoding.UTF8.GetString(plaintext);
}
注:本案例.NET项目使用的是.NET6,Chrome浏览器版本是v110。
Chrome开源地址:chromium.googlesource.com/chromium/src
解密加密地址:
https://cs.chromium.org/chromium/src/components/os_crypt/os_crypt_win.cc?q=OSCrypt&dr=CSs
输出str效果:

C# 大文件数据流分段输出,多段输出,支持视频图片等
为了防止直接请求文件而导致数据被采集,通过接口逻辑判断后再输出文件流的方式模拟完成直接请求文件的操作,支持大文件流操作
C#代码
/// <summary>
/// 文件分段,多段输出
/// </summary>
public class MultipartFileSender
{
protected log4net.ILog logger = log4net.LogManager.GetLogger(typeof(MultipartFileSender));
private const int DEFAULT_BUFFER_SIZE = 20480; // ..bytes = 20KB.
private const string MULTIPART_BOUNDARY = "MULTIPART_BYTERANGES";
string filepath;
readonly HttpRequestBase request;
private HttpResponseBase response;
/// <summary>
/// 初始化
/// </summary>
/// <param name="path">文件物理路径</param>
public MultipartFileSender(string path, HttpRequestBase req, HttpResponseBase resp)
{
filepath = path;
request = req;
response = resp;
}
/// <summary>
/// 输出
/// </summary>
public void ServeResource()
{
if (response == null || request == null)
{
return;
}
if (filepath.IsNullOrWiteSpace() || !File.Exists(filepath))
{
logger.Error($"请求文件不存在 : {filepath}");
response.StatusCode = 404;
response.Flush();
response.Close();
return;
}
FileInfo fileinfo = new FileInfo(filepath);
long length = fileinfo.Length;
string fileName = Path.GetFileName(filepath);
string etag = fileName.GetMd5_16();
DateTime lastModifiedTime = fileinfo.LastWriteTimeUtc;
long lastModified = (long)(lastModifiedTime - new DateTime(1970, 1, 1, 0, 0, 0, 0)).TotalSeconds;
string contentType = MimeMapping.GetMimeMapping(fileName);
// Validate request headers for caching ---------------------------------------------------
// If-None-Match header should contain "*" or ETag. If so, then return 304.
string ifNoneMatch = request.Headers["If-None-Match"];
if (ifNoneMatch != null && HttpMatches(ifNoneMatch, etag))
{
response.AddHeader("ETag", etag); // Required in 304.
response.StatusCode = 304;
response.Flush();
response.Close();
return;
}
// If-Modified-Since header should be greater than LastModified. If so, then return 304.
// This header is ignored if any If-None-Match header is specified.
long ifModifiedSince = request.Headers["If-Modified-Since"]?.ToLong() ?? -1;
if (ifNoneMatch == null && ifModifiedSince != -1 && ifModifiedSince + 1000 > lastModified)
{
response.AddHeader("ETag", etag); // Required in 304.
response.StatusCode = 304;
response.Flush();
response.Close();
return;
}
// Validate request headers for resume ----------------------------------------------------
// If-Match header should contain "*" or ETag. If not, then return 412.
string ifMatch = request.Headers["If-Match"];
if (ifMatch != null && !HttpMatches(ifMatch, etag))
{
response.StatusCode = 412;
response.Flush();
response.Close();
return;
}
// If-Unmodified-Since header should be greater than LastModified. If not, then return 412.
long ifUnmodifiedSince = request.Headers["If-Unmodified-Since"]?.ToLong() ?? -1;
if (ifUnmodifiedSince != -1 && ifUnmodifiedSince + 1000 <= lastModified)
{
response.StatusCode = 412;
response.Flush();
response.Close();
return;
}
// Validate and process range -------------------------------------------------------------
// Prepare some variables. The full Range represents the complete file.
HttpRange full = new HttpRange(0, length - 1, length);
List<HttpRange> ranges = new List<HttpRange>();
// Validate and process Range and If-Range headers.
string range = request.Headers["Range"];
if (range != null)
{
// Range header should match format "bytes=n-n,n-n,n-n...". If not, then return 416.
if (!Regex.IsMatch(range, "^bytes=\\d*-\\d*(,\\d*-\\d*)*$"))
{
response.AddHeader("Content-Range", "bytes */" + length); // Required in 416.
response.StatusCode = 416;
response.Flush();
response.Close();
return;
}
string ifRange = request.Headers["If-Range"];
if (ifRange != null && ifRange != etag)
{
try
{
long ifRangeTime = ifRange.ToLong(); // Throws IAE if invalid.
if (ifRangeTime != -1)
{
ranges.Add(full);
}
}
catch (Exception ignore)
{
ranges.Add(full);
}
}
// If any valid If-Range header, then process each part of byte range.
if (ranges.Count == 0)
{
foreach (var part in range.Substring(6).Split(','))
{
// Assuming a file with length of 100, the following examples returns bytes at:
// 50-80 (50 to 80), 40- (40 to length=100), -20 (length-20=80 to length=100).
long start = HttpRange.Sublong(part, 0, part.IndexOf("-", StringComparison.Ordinal));
long end = HttpRange.Sublong(part, part.IndexOf("-", StringComparison.Ordinal) + 1, part.Length);
if (start == -1)
{
start = length - end;
end = length - 1;
}
else if (end == -1 || end > length - 1)
{
end = length - 1;
}
// Check if Range is syntactically valid. If not, then return 416.
if (start > end)
{
response.AddHeader("Content-Range", "bytes */" + length); // Required in 416.
response.StatusCode = 416;
response.Flush();
response.Close();
return;
}
// Add range.
ranges.Add(new HttpRange(start, end, length));
}
}
}
// Prepare and initialize response --------------------------------------------------------
// Get content type by file name and set content disposition.
string disposition = "inline";
// If content type is unknown, then set the default value.
// For all content types, see: http://www.w3schools.com/media/media_mimeref.asp
// To add new content types, add new mime-mapping entry in web.xml.
if (contentType == null)
{
contentType = "application/octet-stream";
}
else if (!contentType.StartsWith("image"))
{
// Else, expect for images, determine content disposition. If content type is supported by
// the browser, then set to inline, else attachment which will pop a 'save as' dialogue.
string accept = request.Headers["Accept"];
disposition = accept != null && HttpAccepts(accept, contentType) ? "inline" : "attachment";
}
// Initialize response.
response.Clear();
response.ClearContent();
response.ClearHeaders();
response.Buffer = true;
response.AddHeader("Content-Type", contentType);
response.AddHeader("Content-Disposition", disposition + ";filename=\"" + fileName + "\"");
response.AddHeader("Accept-Ranges", "bytes");
response.AddHeader("ETag", etag);
response.Cache.SetLastModified(lastModifiedTime);
response.Cache.SetExpires(DateTime.UtcNow.AddDays(7));
// Send requested file (part(s)) to client ------------------------------------------------
// Prepare streams.
using (FileStream input = new FileStream(filepath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (Stream output = response.OutputStream)
{
if (ranges.Count == 0 || ranges[0] == full)
{
if (logger.IsDebugEnabled)
logger.Info($"Return full file,{filepath}");
response.ContentType = contentType;
response.AddHeader("Content-Range", "bytes " + full.start + "-" + full.end + "/" + full.total);
response.AddHeader("Content-Length", full.length.ToString());
HttpRange.Copy(input, output, length, full.start, full.length);
}
else if (ranges.Count == 1)
{
// Return single part of file.
HttpRange r = ranges[0];
logger.Info($"Return 1 part of file :{fileName}, from ({r.start}) to ({r.end})");
response.ContentType=contentType;
response.AddHeader("Content-Range", "bytes " + r.start + "-" + r.end + "/" + r.total);
response.AddHeader("Content-Length", r.length.ToString());
response.StatusCode = 206;
// Copy single part range.
HttpRange.Copy(input, output, length, r.start, r.length);
}
else
{
// Return multiple parts of file.
response.ContentType="multipart/byteranges; boundary=" + MULTIPART_BOUNDARY;
response.StatusCode = 206;
// Cast back to ServletOutputStream to get the easy println methods.
// Copy multi part range.
foreach (HttpRange r in ranges)
{
if (logger.IsDebugEnabled)
logger.Info($"Return multi part of file :{fileName} from ({r.start}) to ({r.end})");
// Copy single part range of multi part range.
HttpRange.Copy(input, output, length, r.start, r.length);
}
}
}
}
/**
* Returns true if the given accept header accepts the given value.
* @param acceptHeader The accept header.
* @param toAccept The value to be accepted.
* @return True if the given accept header accepts the given value.
*/
public static bool HttpAccepts(string acceptHeader, string toAccept)
{
string[] acceptValues =
acceptHeader.Split(new char[] { ',', '|', ';' }, StringSplitOptions.RemoveEmptyEntries);
return acceptValues.Contains(toAccept)
|| acceptValues.Contains(toAccept.Replace("/.*$", "/*"))
|| acceptValues.Contains("*/*");
}
/**
* Returns true if the given match header matches the given value.
* @param matchHeader The match header.
* @param toMatch The value to be matched.
* @return True if the given match header matches the given value.
*/
public static bool HttpMatches(string matchHeader, string toMatch)
{
string[] matchValues = matchHeader.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
return matchValues.Contains(toMatch)
|| matchValues.Contains("*");
}
class HttpRange
{
public long start;
public long end;
public long length;
public long total;
/**
* Construct a byte range.
* @param start Start of the byte range.
* @param end End of the byte range.
* @param total Total length of the byte source.
*/
public HttpRange(long start, long end, long total)
{
this.start = start;
this.end = end;
this.length = end - start + 1;
this.total = total;
}
public static long Sublong(string value, int beginIndex, int endIndex)
{
string substring = value.Substring(beginIndex, endIndex - beginIndex);
return (substring.Length > 0) ? substring.ToLong() : -1;
}
public static void Copy(Stream input, Stream output, long inputSize, long start, long length)
{
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
int read;
if (inputSize == length)
{
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
output.Write(buffer, 0, read);
output.Flush();
}
}
else
{
input.Seek(start, SeekOrigin.Begin);
long toRead = length;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
if ((toRead -= read) > 0)
{
output.Write(buffer, 0, read);
output.Flush();
}
else
{
output.Write(buffer, 0, (int)toRead + read);
output.Flush();
break;
}
}
}
}
}
}
C#多屏显示方法
使用SetWindowPos设置位置
用Screen
获取当前系统连接的屏幕数量: Screen.AllScreens.Count();
获取当前屏幕的名称:string CurrentScreenName = Screen.FromControl(this).DeviceName;
获取当前屏幕对象:Screen CurrentScreen = Screen.FromControl(this);
获取当前鼠标所在的屏幕:Screen CurrentScreen = Screen.FromPoint(new Point(Cursor.Position.X, Cursor.Position.Y));
Winform下,不需要任何引用直接添加代码,这两行代码表示将一个无边框的窗体全屏显示在第二个窗体上。
this.FormBorderStyle = FormBorderStyle.None;
this.DesktopBounds = Screen.AllScreens[1].Bounds;
获取所有窗体的显示比率:
Screen[] s = Screen.AllScreens;
ScreensRect = new Rectangle[s.Length];
for (int i = 0; i < s.Length; i++)
{
ScreensRect[i] = s[i].WorkingArea;
}
获取第二屏的坐标:
int iX = ScreensRect[1].X;
int iY = ScreensRect[1].Y;
获取当前系统连接的屏幕数量:
Screen.AllScreens.Count();
获取当前屏幕的名称:
string CurrentScreenName = Screen.FromControl(this).DeviceName;
获取当前屏幕对象:
Screen CurrentScreen = Screen.FromControl(this);
获取当前鼠标所在的屏幕:
Screen CurrentScreen = Screen.FromPoint(new Point(Cursor.Position.X, Cursor.Position.Y));
让窗体在第2个屏幕上显示:
this.Left = ((Screen.AllScreens[1].Bounds.Width - this.Width) / 2);
this.Top = ((Screen.AllScreens[1].Bounds.Height - this.Height) / 2);
NET(C#)多屏(双屏)设置屏幕显示器分辨率方法代码(SetRes)
1、SetRes下载
下载地址:https://www.softpedia.com/get/Multimedia/Video/Other-VIDEO-Tools/Ian-Sharpe-SetRes.shtml
2、修改单屏代码
将下载的SetRes.exe拷到当前目录即可
System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
startInfo.FileName = "cmd.exe";
startInfo.Arguments = "/c setres h1920 v1080";
process.StartInfo = startInfo;
process.Start();
3、修改双屏代码
将下载的SetRes.exe拷到当前目录即可
System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
startInfo.FileName = "cmd.exe";
startInfo.Arguments = "/c SETRES m0:0 h1366 v768 && SETRES m1:0 h1280 v800";
process.StartInfo = startInfo;
process.Start();
asp.net网站之状态服务
web.config关于sessionState节点的配置方案,sessionState有四种模式:off,inProc,StateServer,SqlServer。
其中的StateServer会话管理模式配置如下
将mode属性设为StateServer,也就是将会话数据存储到单独的内存缓冲区中,再由单独一台机器上运行
的Windows服务来控制这个缓冲区。状态服务全称是“ASP.NET State Service ”(aspnet_state.exe),计算机管理-服务 里面即可看到此服务,启动该服务j
它由Web.config文件中的stateConnectionString属性来配置。该属性指定了服务所在的服务器,以及要监
视的端口:
<sessionState mode="StateServer"
stateConnectionString="tcpip=myserver:42424"
cookieless="false" timeout="20" />
在这个例子中,状态服务在一台名为myserver的机器的42424端口(默认端口)运行。要在服务器上改变
端口,可编辑HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\aspnet_state\Parameters注册表项中的Port值。
显然,使用状态服务的优点在于进程隔离,并可在Web farm(网站群)中共享。 使用这种模式,会话状态的存储将不
依赖于iis进程的失败或者重启,然而,一旦状态服务中止,所有会话数据都会丢失。换言之,状态服务不
像SQL Server那样能持久存储数据;它只是将数据存储在内存中。
解决之前问题的方法很简单:
1. 状态服务可以开在第三台机子C上,此服务器专门存放用户上传文件,状态,日志等。
2. 修改C机子上的注册表,将
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\aspnet_state\Parameters
中的AllowRemoteConnection设置成1,还可以改端口,将Port设置你想要的值即可,此值默认42424。
3. 配置A,B应用服务器上网站的web.config中状态配置项如下:
<sessionState mode="StateServer"
stateConnectionString="tcpip=C服务器的IP:42424"
cookieless="false" timeout="20" />
然后在TNS服务器上添加网站域名和A,B服务器的IP映射即可
cookieless="false"表示:如果用户浏览器支持Cookie时启用会话状态(默认为False)
cookieless="true"表示:如果用户浏览器不支持Cookie时启用会话状态(默认为False)
C#界面UI框架
RealTaiiZor
安装:install-Package ReaLTaiiizor -Version 3
CSkin
SunnyUI
.netbar
C# 实现监控文件夹和里面文件的变化
描述:
FileSystemWatcher位于System.IO;
命名空间下面,想要使用它必须先引用System.IO;
下面的例子使用了FileSystemWatcher来监控C盘文件的变化,因为这个目录的变化是最频繁的,运行程序打开浏览器可以看到很频繁的临时文件创建,需要注意的是:
添加文件或文件夹时,会触发Created事件,然后修改默认文件夹或文件名称再触发Changed事件。
复制或移动文件夹文件时则是触发Created事件。
删除文件夹或文件时触发Deleted事件。
下面是整个例子的代码,可以建一个空的控制台应用程序复制粘贴就能运行了:
复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace HelloCsharp
{
class Program
{
static void Main(string[] args)
{
FileListenerServer f1 = new FileListenerServer(@"c:\");
f1.Start();
Console.ReadKey();
}
}
public class FileListenerServer
{
private FileSystemWatcher _watcher;
public FileListenerServer()
{
}
public FileListenerServer(string path)
{
try
{
this._watcher = new FileSystemWatcher();
_watcher.Path = path;
_watcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.DirectoryName;
_watcher.IncludeSubdirectories = true;
_watcher.Created += new FileSystemEventHandler(FileWatcher_Created);
_watcher.Changed += new FileSystemEventHandler(FileWatcher_Changed);
_watcher.Deleted += new FileSystemEventHandler(FileWatcher_Deleted);
_watcher.Renamed += new RenamedEventHandler(FileWatcher_Renamed);
}
catch (Exception ex)
{
Console.WriteLine("Error:" + ex.Message);
}
}
public void Start()
{
this._watcher.EnableRaisingEvents = true;
Console.WriteLine("文件监控已经启动...");
}
public void Stop()
{
this._watcher.EnableRaisingEvents = false;
this._watcher.Dispose();
this._watcher = null;
}
protected void FileWatcher_Created(object sender, FileSystemEventArgs e)
{
Console.WriteLine("新增:" + e.ChangeType + ";" + e.FullPath + ";" + e.Name);
}
protected void FileWatcher_Changed(object sender, FileSystemEventArgs e)
{
Console.WriteLine("变更:" + e.ChangeType + ";" + e.FullPath + ";" + e.Name);
}
protected void FileWatcher_Deleted(object sender, FileSystemEventArgs e)
{
Console.WriteLine("删除:" + e.ChangeType + ";" + e.FullPath + ";" + e.Name);
}
protected void FileWatcher_Renamed(object sender, RenamedEventArgs e)
{
Console.WriteLine("重命名: OldPath:{0} NewPath:{1} OldFileName{2} NewFileName:{3}", e.OldFullPath, e.FullPath, e.OldName, e.Name);
}
}
}
C# 动态拦截第三方进程中的方法函数
原文2
一、前言
由于项目需要,最近研究了一下跨进程通讯改写第三方程序中的方法(运行中),把自己程序中的目标方法直接覆盖第三方程序中的方法函数;一直没有头绪,通过搜索引擎找了一大堆解决方案,资料甚是稀少,最后功夫不负有心人,经过两天的研究,终于在github 上找到两个开源的代码,通过两个开源代码结合起来即可实现我的需求。下面进一步来分析实践原理,后面会把源代码地址贴上来;
通过该文章分享,你会知道怎样通过注入一个dll模块改写第三方运行的程序中的某个方法,在里面实现自己的业务,这个场景在做外挂程序中特别实用!!!
二、场景
假如有一个第三方应用程序,这时候需要对第三方应用程序进行方法拦截,比如第三方应用程序中的某个操作需要用我们的业务覆盖掉他们的业务,那这种情况下我们有什么好的方案解决呢?我们不可能修改第三方程序的代码,那有什么方案可以解决呢?其实我们还是有办法进行”修改“第三方程序的代码的,怎么”修改“呢,请看下面实践原理,下面带你走入不一样的代码世界!!!!
三、实践
原理简化图:
这里实践我就直接写两个客户端程序来进行代码上的演示
3.1. 实现原理
Hook 目标方法:
需要改写拦截第三方程序的指定的方法,那就得需要Hook 该方法,经过查找资料在github上找到开源代码DotNetDetour,但是开源作者是从.net framework 4.5开始支持,不支持.net framework 4.0, 我的需求需要运行在老爷机xp 上,故必须要支持4.0 的框架,所有我fork了一份把源代码做了修改支持到了.net framework 4.0 框架,fork 源代码地址:https://github.com/a312586670/DotNetDetour
Inject 注入dll到目标进程
写好针对目标进程的方法Hooke dll 模块后需要考虑把该dll模块注入到第三方程序进程中,这样才可以实现完全的hook成功,改写目标进程的方法,我这里使用fastWin32 开源代码,代码地址如下:https://github.com/a312586670/FastWin32
3.2 创建第三方程序Demo
这里为了演示,我自己创建了一个目标客户端程序,主要有如下核心代码方法:
public class ProcessService
{ public string GetProcessInfo()
{ return "这是TargetClient 客户端(第三方程序)";
} public ProcessResponse GetProcessInfo(ProcessRequest request)
{ return new ProcessResponse()
{
Name = "这是TargetClient 客户端(第三方程序)",
Version = request.Version
};
}
}
UI界面交互代码如下:
/// <summary>
/// MainWindow.xaml 的交互逻辑 /// </summary>
public partial class MainWindow : Window
{ public MainWindow()
{
InitializeComponent();
} private void btnInfo_Click(object sender, RoutedEventArgs e)
{ var service = new ProcessService(); this.txtInfo.Text = service.GetProcessInfo();
} private void btnComplateInfo_Click(object sender, RoutedEventArgs e)
{ var service = new ProcessService(); var response = service.GetProcessInfo(new ProcessRequest() { Version = "v-Demo 1.0 版本" }); this.txtInfo.Text = response.Name + response.Version;
}
}
上面代码中有两个按钮事件,分别调用了ProcessService 的两个方法,我们先来运行目标客户端Demo程序,分别点击两个按钮运行结果如下:
按钮事件结果1
按钮事件结果2
3.3 创建核心Hook类库
好了,上面我们的目标第三方Demo程序已经写好了,接下来我们需要写一个核心的Jlion.Process.HookCore类库 改写目标的ProcessService 的两个方法。
我这里建了一个Jlion.Process.HookCore类库,通过nuget包引用我fork 后的DotNetDetour 类库,如下图:
应用成功后我们建立核心的hook 方法,代码如下:
public class ProcessHookService : IMethodHook
{
[HookMethod("Jlion.Process.Target.Client.ProcessService", null, null)] public string GetProcessInfo()
{
TextHelper.LogInfo($"这是Jlion.Process.HookCore.HookService dll. 改写TargetClient 客户端 的GetProcessInfo 方法后得到的结果"); return "这是Jlion.Process.HookCore.HookService dll. 改写TargetClient 客户端 的GetProcessInfo 方法后得到的结果";
}
[OriginalMethod] public string GetProcessInfo_Original()
{ return null;
}
[HookMethod("Jlion.Process.Target.Client.ProcessService", null, null)] public object GetProcessInfo([RememberType("Jlion.Process.Target.Client.Model.ProcessRequest", false)] object request)
{ var json = JsonConvert.SerializeObject(request);
TextHelper.LogInfo($"json:{json}"); var name = "这是Jlion.Process.HookCore.HookService dll. 改写TargetClient 客户端的GetProcessInfo(obj)后得到的结果"; return new ProcessResponse()
{
Name = name,
Version = "改写的dll 版本"
};
}
[OriginalMethod] public object GetProcessInfo_Original([RememberType("Jlion.Process.Target.Client.Model.ProcessRequest", false)] object request)
{ return null;
}
}
我这里就不详细的写DotNetDetour 的使用,需要知道它的使用可以访问 https://github.com/a312586670/DotNetDetour 查看具体的文档
核心的Jlion.Process.HookCore hook 类库 也已经创建完了,接下来还需要创建一个初始化Hook的服务类(特别重要),并且还必须是静态方法,代码如下:
public class HookService
{ /// <summary>
/// Hook 初始化 /// </summary>
/// <param name="msg"></param>
/// <returns></returns>
public static int Start(string msg)
{ try
{
TextHelper.LogInfo("开始"+msg);
MethodHook.Install();
} catch
{ return -1;
} return 1;
}
}
到这一步基本上Jlion.Process.HookCore Hook 核心的类库已经创建完了
3.4 模块注入客户端程序
创建客户端后需要引用FastWin32类库,如下图:
客户端注入Dll核心代码如下:
public class InjectService
{ //注入的核心dll 路径
public static string path = AppDomain.CurrentDomain.BaseDirectory+ "Jlion.Process.HookCore.dll"; /// <summary>
/// 进程id /// </summary>
public static uint pid = 0; /// <summary>
/// 启动 /// </summary>
public static void Start()
{
Inject();
} #region 私有方法 private static void Inject()
{ try
{
Injector.InjectManaged(pid, path, "Jlion.Process.HookCore.HookService", "Start", "ss", out int returnValue);
} catch (Exception ex)
{
}
}
#endregion
}
代码中核心的代码是Injector.InjectManaged(),该方法有如下两个重构方法:
参数说明:
processId:目标进程的进程id ->pid
assemblyPath:核心Hook 注入的dll 绝对路径
typeName:Hook 初始化方法的命名空间,一般注入一个模块dll后需要执行的入口初始化方法,这里是Hook 核心dll 中的HookService.Start 方法的命名空间(Jlion.Process.HookCore.HookService)
methodName : 注入后执行的方法名称
argument : 方法所需要的参数
returnValue:返回注入后运行的方法返回值
客户端UI 核心代码如下:
/// <summary>
/// MainWindow.xaml 的交互逻辑 /// </summary>
public partial class MainWindow : Window
{ public MainWindow()
{
InitializeComponent();
} private void btnInject_Click(object sender, RoutedEventArgs e)
{
InjectService.pid = Convert.ToUInt32(txbPid.Text.Trim());
InjectService.Start();
}
}
这里核心的注入Client Demo 也写完了,我们把注入的客户端也运行起来,输入目标的进程pid(也可以程序中查找目标进程Id),运行后再来执行上面创建的第三方程序的两个按钮,结果如下:
通过编写客户端程序点击注入dll后,再点击第三方程序的两个按钮事件,结果如下:
可以看到点击后,运行的结果已经被动态注入的Jlion.Process.HookCore.dll改写了,不过上面的代码也可以改写后同时还运行原有目标的方法就是通过调用'_Original'后缀结尾的方法,方法体返回null即可。
四、总结
通过DotNetDetour 框架可以编写对目标进程的方法进行Hook 重写,使用新的方法覆盖第三方进程的方法,也可以继续执行第三方的方法。
通过FastWin32调用Win32 API 把开发的dll模块注入到第三方进程中,同时注入后执行初始化方法,可以进行原有的Hook方法进行覆盖。
到这里是不是感觉很神奇,它可以在以下场景中使用:
想必大家想到的就是外挂程序,通过改写目标程序的方法进行外挂处理,写上自己的覆盖业务
灰产地带比较实用
破解第三方收费软件等等用途
感兴趣的朋友可以下载Demo 源代码玩一玩:
github 源代码地址:https://github.com/a312586670/processClientDemo
使用共享资源建立IIS虚拟目录
p.s. 关键就在文件服务器上面必须建立一个和web服务器完全一样的帐号(包括用户名和密码)
假设有 web服务器( webserver ) 和 文件服务器( fileserver )
1、web服务器上建立帐号 webuser1 密码123456
2、web服务器的IIS上建立一个虚拟目录,将主目录指到 \\fileserver\web1 ,虚拟目录安全性下的身份验证填写 帐号 webuser1 密码123456
3、file服务器上建立相同帐号 webuser1 密码123456
4、file服务器上建立目录web1,赋予webuser1 可读写,并共享
注意
1、这个目录是直接输入的,不是通过浏览选择的,就跟访问网络共享通过我的电脑运行中输入的的路径一样;
2、如果这个目录是通过建立虚拟目录到一个站点,那么要使这个站点有访问共享目录的权限要把该站点的匿名访问改成webuser1用户登录
C#嵌入x86汇编——一个GPIO接口的实现
开始进入工业自动化,买的工控机带有GPIO接口,可用于直接控制继电器。
从厂家拿到接口手册一看,居然是汇编直接操作端口,基本上是IN/OUT指令了。接口很简单,计算位移,读取;计算位移,写入。
这种接口,常见有四种办法,分别是四种语言实现,一是直接写ASM,不过要公开给C#做的应用程序调用,很不容易,另外三种是C/C++/Delphi嵌入汇编,倒是问题不大。
接口实在是小,不想大动干戈,所以想了别的办法。
第五种,用C++/CLI,这也是一个不错的主意。但是我甚至想省掉这个接口DLL,于是有了第六种办法:C#嵌入x86汇编。
C#是没办法像C/C++/Delphi那样直接嵌入x86汇编的,所以需要做点手脚。
在汇编里面,我们为了修改一个软件经常找一块空白区域来写汇编代码,然后Jmp过去执行。(不明白这一句话的可以跳过,或者去看雪论坛)
但是显然要在C#代码里面这么做很不现实,即使用C/C++编译得到obj,C#也没办法链接这个obj。(这个涉及编译的也可以跳过)
回头一想(其实不是现在想,07年就做过C#嵌入汇编),其实C#也跑在x86上,IL指令最终还是要编译成x86汇编指令的,我们应该可以这些写汇编指令,所需要的只是一块空间而已。
我们可以申请一块非托管空间嘛,于是有:
// 分配内存var ptr = Marshal.AllocHGlobal(code.Length);
有了空间,我们就可以把二进制的汇编指令给写进去啦:
// 写入汇编指令Marshal.Copy(code, 0, ptr, code.Length);
然后呢?.Net提供一个途径,让我们可以把一个内存指针转为一个委托(一直都说.Net的委托其实就是C/C++的函数指针哈):
// 转为委托return (T)(Object)Marshal.GetDelegateForFunctionPointer(ptr, typeof(T));
那么,剩下的问题,就是如何把汇编转为二进制了!
这个我们是不能像C/C++/Delphi那样直接写汇编指令的,所以得走点弯路。
我的做法是用OD随便打开一个程序,在上面直接写汇编代码,然后把汇编的十六进制复制出来,放到C#代码中。
剩下的就不多说了,直接上代码吧!
GPIO接口实现
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.IO;
namespace ConsoleApplication19
{
class GPIO
{
#region 属性
private Int32 _Offset;
/// <summary>选择位移</summary>
public Int32 Offset { get { return _Offset; } set { _Offset = value; } }
private Int32 _Bit;
/// <summary>选择位</summary>
public Int32 Bit { get { return _Bit; } set { _Bit = value; } }
#endregion
#region 构造
private GPIO(Int32 offset, Int32 bit)
{
Offset = offset;
Bit = bit;
}
private GPIO(Int32 gpio)
{
Offset = gpio / 16;
Bit = gpio % 16;
}
#endregion
#region 预定义针脚
public static GPIO Pin2 = new GPIO(0, 6);
public static GPIO Pin3 = new GPIO(0, 7);
public static GPIO Pin4 = new GPIO(2, 1);
public static GPIO Pin5 = new GPIO(2, 4);
public static GPIO Pin6 = new GPIO(1, 0);
public static GPIO Pin7 = new GPIO(1, 4);
public static GPIO Pin8 = new GPIO(3, 3);
public static GPIO Pin9 = new GPIO(3, 4);
public static GPIO IO6 = new GPIO(6);
public static GPIO IO7 = new GPIO(7);
public static GPIO IO17 = new GPIO(17);
public static GPIO IO20 = new GPIO(20);
public static GPIO IO8 = new GPIO(8);
public static GPIO IO12 = new GPIO(12);
public static GPIO IO27 = new GPIO(27);
public static GPIO IO28 = new GPIO(28);
#endregion
#region 业务
/// <summary>是否启用</summary>
public Boolean Enable { get { return Read(Offset, Bit); } set { WriteBit(Offset, Bit, value); } }
/// <summary>是否输出</summary>
public Boolean Output { get { return Read(Offset + 4, Bit); } set { WriteBit(Offset + 4, Bit, value); } }
/// <summary>是否设置数据位</summary>
public Boolean Data { get { return Read(Offset + 12, Bit); } set { WriteBit(Offset + 12, Bit, value); } }
#endregion
#region 读取端口
const Int16 BASEADDRESS = 0x500;
Boolean Read(Int32 offset, Int32 bit)
{
var d = ReadHandler((Int16)(BASEADDRESS + offset));
var c = (Byte)~(1 << bit);
d &= c;
return d == c;
}
private static ReadFunc _ReadHandler;
/// <summary>属性说明</summary>
public static ReadFunc ReadHandler { get { return _ReadHandler ?? (_ReadHandler = GetReadHandler()); } }
//static IntPtr ptr;
static ReadFunc GetReadHandler()
{
// 汇编指令
var code = new Byte[] {
0x66, 0x8B, 0x55, 0x08, //mov dx, word ptr [ebp+8]
0xEC, //in al, dx
};
return (ReadFunc)InjectASM<ReadFunc>(code);
}
public delegate Byte ReadFunc(Int16 address);
#endregion
#region 写入端口
void Write(Int32 offset, Int32 value)
{
WriteHandler((Int16)(BASEADDRESS + offset), (Byte)value);
}
private static WriteFunc _WriteHandler;
/// <summary>属性说明</summary>
public static WriteFunc WriteHandler { get { return _WriteHandler ?? (_WriteHandler = GetWriteHandler()); } }
static WriteFunc GetWriteHandler()
{
// 汇编指令
var code = new Byte[] {
0x66, 0x8B, 0x55, 0x08, //mov dx, word ptr [ebp+8]
0x8A, 0x45, 0x0C, //mov al, byte ptr [ebp+C]
0xEE //out dx, al
};
return InjectASM<WriteFunc>(code);
}
public delegate void WriteFunc(Int16 address, Byte bit);
#endregion
#region 写入端口位
void WriteBit(Int32 offset, Int32 bit, Boolean value)
{
if (value)
SetBitHandler((Int16)(BASEADDRESS + offset), (Byte)bit);
else
ClearBitHandler((Int16)(BASEADDRESS + offset), (Byte)bit);
}
private static WriteBitFunc _SetBitHandler;
/// <summary>设置位</summary>
public static WriteBitFunc SetBitHandler { get { return _SetBitHandler ?? (_SetBitHandler = GetSetBitHandler()); } }
private static WriteBitFunc _ClearBitHandler;
/// <summary>清除位</summary>
public static WriteBitFunc ClearBitHandler { get { return _ClearBitHandler ?? (_ClearBitHandler = GetClearBitHandler()); } }
static WriteBitFunc GetSetBitHandler()
{
// 汇编指令
var code = new Byte[] {
0x53, //push ebx
0x51, //push ecx
0x66, 0x8B, 0x55, 0x08, //mov dx, word ptr [ebp+8]
0x8A, 0x45, 0x0C, //mov al, byte ptr [ebp+C]
0xB3, 0x01, //mov bl, 1
0xD2, 0xE3, //shl bl, cl
0xEC, //in al, dx
0x08, 0xD8, //or al, bl
0xEE, //out dx, al
0x59, //pop ecx
0x5B //pop ebx
};
return InjectASM<WriteBitFunc>(code);
}
static WriteBitFunc GetClearBitHandler()
{
// 读出字节,取消指定位后重新写回去
var code = new Byte[] {
0x53, //push ebx
0x51, //push ecx
0x66, 0x8B, 0x55, 0x08, //mov dx, word ptr [ebp+8]
0x8A, 0x45, 0x0C, //mov al, byte ptr [ebp+C]
0xB3, 0x01, //mov bl, 1
0xD2, 0xE3, //shl bl, cl
0xF6, 0xD3, //not bl
0xEC, //in al, dx
0x20, 0xD8, //and al, bl
0xEE, //out dx, al
0x59, //pop ecx
0x5B, //pop ebx
};
return InjectASM<WriteBitFunc>(code);
}
public delegate void WriteBitFunc(Int16 address, Byte bit);
#endregion
#region 注入汇编
static T InjectASM<T>(Byte[] code)
{
// 汇编指令
var code1 = new Byte[] {
0x55, //push ebp
0x8B, 0xEC, //mov ebp, esp
0x52, //push edx
};
var code2 = new Byte[] {
0x5A, //pop edx
0x8B, 0xE5, //mov esp, ebp
0x5D, //pop ebp
0xC3 //ret
};
//var cbs = new Byte[code1.Length + code.Length + code2.Length];
var ms = new MemoryStream();
ms.Write(code1, 0, code1.Length);
ms.Write(code, 0, code.Length);
ms.Write(code2, 0, code2.Length);
code = ms.ToArray();
// 分配内存
var ptr = Marshal.AllocHGlobal(code.Length);
// 写入汇编指令
Marshal.Copy(code, 0, ptr, code.Length);
// 设为可执行
VirtualProtectExecute(ptr, code.Length);
Console.WriteLine("0x{0:X8}", ptr.ToInt32());
Console.ReadKey(true);
// 转为委托
return (T)(Object)Marshal.GetDelegateForFunctionPointer(ptr, typeof(T));
}
#endregion
#region 辅助
//[DllImport("kernel32.dll", SetLastError = true)]
//static extern int VirtualQueryEx(int hProcess, ref object lpAddress, ref MEMORY_BASIC_INFORMATION lpBuffer, int dwLength);
[DllImport("kernel32.dll", SetLastError = true)]
static extern int VirtualProtectEx(IntPtr hProcess, IntPtr lpAddress, int dwSize, int flNewProtect, ref int lpflOldProtect);
static Boolean VirtualProtectExecute(IntPtr address, Int32 size)
{
const Int32 PAGE_EXECUTE_READWRITE = 0x40;
Int32 old = 0;
return VirtualProtectEx(Process.GetCurrentProcess().Handle, address, size, PAGE_EXECUTE_READWRITE, ref old) == 0;
}
#endregion
}
}
C# Hprose轻量级、跨语言、跨平台的面向对象的高性能远程动态通讯中间件
Hprose (High Performance Remote Object Service Engine) 是一个MIT开源许可的新型轻量级跨语言跨平台的面向对象的高性能远程动态通讯中间件。它支持众多语言,例如nodeJs, C++, .NET, Java, Delphi, Objective-C, ActionScript, JavaScript, ASP, PHP, Python, Ruby, Perl, Golang 等语言,通过 Hprose 可以在这些语言之间实现方便且高效的互通。
Hprose 易学易用,且功能强大,您只需很短时间的学习,就可以用它方便地构建出跨语言跨平台分布式的电信级应用系统。
国内码云git项目下载地址
https://gitee.com/andot/hprose-dotnet
github地址
https://github.com/hprose/hprose-dotnet
服务端代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Hprose.Server;
namespace HproseTcpServerTest {
class Program {
public static string Hello(string name) {
return "Hello " + name + "!";
}
public static List<object> GetList(string word)
{
List<object> list = new List<object>();
for (int i = 0; i < 100; i++)
{
list.Add(word);
}
return list;
}
static void Main(string[] args) {
try
{
HproseTcpListenerServer tcpserver = new HproseTcpListenerServer("tcp4://127.0.0.1:4321/");
tcpserver.Add("Hello", typeof(Program));
tcpserver.Add("GetList", typeof(Program));
tcpserver.Start();
HproseHttpListenerServer httpserver = new HproseHttpListenerServer("http://localhost:8888/");
httpserver.Add("Hello", typeof(Program));
httpserver.Add("GetList", typeof(Program));
httpserver.Start();
Console.WriteLine("服务已启动");
Console.ReadKey();
tcpserver.Stop();
httpserver.Stop();
}
catch (Exception ex)
{
Console.WriteLine("启动异常:"+ex.Message);
}
}
}
}
客户端代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Hprose.Client;
using System.Diagnostics;
using System.Threading;
namespace HproseTcpClientTest
{
public interface IHello
{
string Hello(string name);
/// <summary>
/// 得到集合
/// </summary>
/// <param name="word"></param>
/// <returns></returns>
List<object> GetList(string word);
}
class Program
{
static IHello hello;
static void Test(string data) {
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int i = 0; i < 1000; i++) {
//hello.Hello(data);
hello.GetList(data);
}
stopwatch.Stop();
Console.WriteLine(stopwatch.Elapsed);
}
static void Main(string[] args)
{
HproseClient client = HproseClient.Create("tcp4://127.0.0.1:4321/");
hello = client.UseService<IHello>();
//20秒后执行
while (true)
{
if (DateTime.Now.Second == DateTime.Parse("2018-04-19 16:43:20").Second)
{
break;
}
Thread.Sleep(500);
}
Console.WriteLine("TCP");
//Console.WriteLine(hello.Hello("World"));
Test("World");
Test("".PadRight(512, '苏'));
Test("".PadRight(1024, '苏'));
Test("".PadRight(2 * 1024, '苏'));
Test("".PadRight(4 * 1024, '苏'));
Test("".PadRight(8 * 1024, '苏'));
Test("".PadRight(16 * 1024, '苏'));
Test("".PadRight(32 * 1024, '苏'));
Test("".PadRight(64 * 1024, '苏'));
Console.WriteLine("完成");
client = HproseClient.Create("http://localhost:8888/");
hello = client.UseService<IHello>();
Console.WriteLine("HTTP");
//Console.WriteLine(hello.Hello("World"));
Test("World");
Test("".PadRight(512, '苏'));
Test("".PadRight(1024, '苏'));
Test("".PadRight(2 * 1024, '苏'));
Test("".PadRight(4 * 1024, '苏'));
Test("".PadRight(8 * 1024, '苏'));
Test("".PadRight(16 * 1024, '苏'));
Test("".PadRight(32 * 1024, '苏'));
Test("".PadRight(64 * 1024, '苏'));
Console.WriteLine("完成");
Console.ReadKey();
// client.Invoke<string>("hello", new Object[] { "Async World" }, result => Console.WriteLine(result));
}
}
}
解决使用JSON JavaScriptSerializer 进行序列化或反序列化时出错。字符串的长度超过了为 maxJsonLength属性
前言
在.net mvc的控制器中,我们在写一些返回json数据的方法,一般会写成return Json(obj);但这种返回类型如果是obj数据过大的话,这时候就会报错因此我们需要改变一下返回类型
常见写法
在.net mvc的controller中,方法返回JsonResult,一般我们这么写:
[HttpPost]
public JsonResult GetKnowledgeSolrList()
{
var str = "";//大数据
return Json(str);
}
此时如果str过长,就会报“使用 JSON JavaScriptSerializer 进行序列化或反序列化时出错,字符串的长度超过了为 maxJsonLength 属性设置的值”。
解决办法
1、在web.config增加如下节点到configuration下,这边我们直接设置成最大值2147483647。
<system.web.extensions>
<scripting>
<webServices>
<jsonSerialization maxJsonLength="2147483647" />
</webServices>
</scripting>
</system.web.extensions>
2、返回方法调整成
[HttpPost]
public JsonResult GetKnowledgeSolrList()
{
var str = "";//大数据
return new JsonResult()
{
Data = str,
MaxJsonLength = int.MaxValue,
ContentType = "application/json"
};
}
C#只运行一个实例
bool createNew;
using (System.Threading.Mutex mutex = new System.Threading.Mutex(true, Application.ProductName, out createNew))
{
if (createNew)
{
Application.Run(new Form1());
}
else
{
MessageBox.Show("应用程序已经在运行中...")
System.Threading.Thread.Sleep(1000);
System.Environment.Exit(1);
}
}
c#实现Javascript的encodeURIComponent()函数
国内外各搜索引擎,均用JavaScript的encodeURIComponent()函数对搜索关键字进行编码,终于找到了.net下的实现方法。
.net采用
System.Text;
UrlDecode(String, Encoding)
使用指定的编码对象将 URL 编码的字符串转换为已解码的字符串。
C#获得重定向地址
C#获得重定向地址,为避免代码造成手机端排版的混乱,可适当增加文字描述,将代码往后推移
HttpWebRequest httpReq = (HttpWebRequest)WebRequest.Create("http://www.contoso.com");
httpReq.AllowAutoRedirect = false;
HttpWebResponse httpRes = (HttpWebResponse)httpReq.GetResponse();
if (httpRes.StatusCode==HttpStatusCode.Moved)
{
// Code for moved resources goes here.
}
// Close the response.
httpRes.Close();
string newUrl = httpRes.Headers["Location"];//获取重定向的网址
httpRes.Headers["Location"];//获取重定向的网址
通过锁字符串达到控制并发的效果C#
通过锁字符串达到控制并发的效果C#
而.net有内部机制使得相同的字符串内存地址是相同的(new string)除外
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
List<string> keyList = new List<string> { "key1", "key2", "key1", "key1", "key1", "key1", };
keyList.ForEach(u =>
{
ThreadPool.QueueUserWorkItem(s =>
{
Test.lockTestByString(u);
});
});
Console.Read();
}
}
public class Test
{
public static void lockTestByString(string key)
{
lock (key)
{
GCHandle handle = GCHandle.Alloc(key, GCHandleType.Pinned);
//获取内存地址
IntPtr address = handle.AddrOfPinnedObject();
Console.WriteLine("上锁2s key=" + key + " 内存地址:" + address);
Thread.Sleep(2000);
Console.WriteLine("解锁");
}
}
}
}
ASP.NET JAVA Go的非对称加密和AES对称加解密
//JAVA端代码
// Java,需要以下引用:
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.*;
import static java.util.Base64.getEncoder;
//另外需要对String和byte[]相互转换的类,我自己写的Base64Helper
// @author miracle.qu
// @see AES算法加密明文
// @param data 明文
// @param key 密钥,长度16
// @param iv 偏移量,长度16
//@return 密文
public class Main {
public static String encryptAES(String data,String key,String iv) throws Exception {
try {
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
int blockSize = cipher.getBlockSize();
byte[] dataBytes = data.getBytes("utf-8");
int plaintextLength = dataBytes.length;
if (plaintextLength % blockSize != 0) {
plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize));
}
byte[] plaintext = new byte[plaintextLength];
System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);
SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
byte[] encrypted = cipher.doFinal(plaintext);
return Base64.getEncoder().encodeToString(encrypted );
//return Base64Helper.encode(encrypted).trim();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
// @author miracle.qu
// @see AES算法解密密文
// @param data 密文
// @param key 密钥,长度16
//@param iv 偏移量,长度16
//@return 明文
public static String decryptAES(String data,String key,String iv) throws Exception {
try
{
byte[] encrypted1 = Base64.getDecoder().decode(data);
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
byte[] original = cipher.doFinal(encrypted1);
String originalString = new String(original);
return originalString.trim();
}
catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeySpecException {
String data="";
try {
data=encryptAES("xn忠魂", "aaabbbcccdddeeef", "1234567890abcdef");
System.out.println(data);
}catch(Exception e)
{
System.out.println(e.toString());
}
try
{
String outString=decryptAES(data,"aaabbbcccdddeeef", "1234567890abcdef");
System.out.println(outString);
}catch(Exception e)
{
System.out.println(e.toString());
}
String src="中华";
String publicKeyString="MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDVTy+1uRxJeWtkPAm/y7CSix0LS148IeU4NXPbR8DEiT6m26wz9OYR9/Aj2Z64ncQBytsQlHUI5opmRFtkDGqgfKadhG0GcAQMRCH/wNCFKdJX20TAdHtJ1jTzQb/vrd0EszPR247Z5jeQMMGtyQbZO9xvDL4jOAqur4dCigFLhQIDAQAB";
String privateKeyString="MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBANVPL7W5HEl5a2Q8Cb/LsJKLHQtLXjwh5Tg1c9tHwMSJPqbbrDP05hH38CPZnridxAHK2xCUdQjmimZEW2QMaqB8pp2EbQZwBAxEIf/A0IUp0lfbRMB0e0nWNPNBv++t3QSzM9HbjtnmN5Awwa3JBtk73G8MviM4Cq6vh0KKAUuFAgMBAAECgYACpWnVGkfEjZIMe0Yvr+ov1zP0COpRWqZKTTdzt+8nQQCa90yqlFYqUOYUu8VhSuu8jfSrvvu4sYtz+1Ma6aCE+VWBuXIAEBI9LsE78GNKyYTJ72uEt0VEMSRmyEMbspvMMsbQFMA9zL1qWC14eNEAghlYUk5MbeAykji6aWnnAQJBAP3z2k8+sZx+MDA05nvP41lcqDsdLfl7TtARsTm8e73DLMjdM7S37z2yoGJ+bv13p2rftgIHUTiXBHKqDmQ0I8UCQQDXB3Kc3T8Tqf3FtDOGHElkRf7pEIr9XfwnpLLdieuuw6BQq/71TSOoc5dzonNKTtsxEqHZtkYihXj752U5ikTBAkB0odEqwf1qhR32leUhCfo9aWuuMpmR0gsBTo7ZmHIwVfo0ijscDbnn2SkF81FgQdr3H6WEyv2Hgvw8+VNAvB2NAkAoW1F7d1q7ShBC5ss0xGJR24E4JM6xNs54ckTPp28AYd7YxS8Ywt2KZAdswHR64cnpr+GIhtkq6XoHbSpmXjkBAkEA8HP1XnU7F69JjSi0GJZK2I03LiU6K9QIZH5NcdDaxAwvWrlDjT0Im2uiwcRXCyaH/57zJ4iuIqfJmLG6Df5f4g==";
RSAPrivateKey rsaprivateKey;
RSAPublicKey rsapublicKey;
try {
//PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(rsaprivateKey.getEncoded());
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKeyString));
KeyFactory privateKeyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = privateKeyFactory.generatePrivate(pkcs8EncodedKeySpec);
Cipher privateCipher = Cipher.getInstance("RSA");
privateCipher.init(Cipher.ENCRYPT_MODE, privateKey);
byte[] result = privateCipher.doFinal(src.getBytes());
//System.out.println("私钥加密,公钥解密--加密:"+Base64.encodeBase64String(result));
System.out.println("私钥加密,公钥解密--加密:" + Base64.getEncoder().encodeToString(result));
//私钥加密,公钥解密--解密
//X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(rsapublicKey.getEncoded());
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(publicKeyString));
KeyFactory publicKeyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = publicKeyFactory.generatePublic(x509EncodedKeySpec);
Cipher publicCipher = Cipher.getInstance("RSA");
publicCipher.init(Cipher.DECRYPT_MODE, publicKey);
result = publicCipher.doFinal(result);
System.out.println("私钥加密,公钥解密--解密:" + new String(result));
//公钥加密,私钥解密---加密
//x509EncodedKeySpec = new X509EncodedKeySpec(rsapublicKey.getEncoded());
x509EncodedKeySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(publicKeyString));
publicKeyFactory = KeyFactory.getInstance("RSA");
publicKey = publicKeyFactory.generatePublic(x509EncodedKeySpec);
publicCipher = Cipher.getInstance("RSA");
publicCipher.init(Cipher.ENCRYPT_MODE, publicKey);
result = publicCipher.doFinal(src.getBytes());
//System.out.println("公钥加密,私钥解密---加密:"+Base64.encodeBase64String(result));
System.out.println("公钥加密,私钥解密---加密:" + Base64.getEncoder().encodeToString(result));
//公钥加密,私钥解密---解密
//pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(rsaprivateKey.getEncoded());
pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKeyString));
privateKeyFactory = KeyFactory.getInstance("RSA");
privateKey = privateKeyFactory.generatePrivate(pkcs8EncodedKeySpec);
privateCipher = Cipher.getInstance("RSA");
privateCipher.init(Cipher.DECRYPT_MODE, privateKey);
result = privateCipher.doFinal(result);
System.out.println("公钥加密,私钥解密---解密:" + new String(result));
}
catch(Exception ex)
{
System.out.println(ex.toString());
}
}
}
DotNot的
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Security.Cryptography;
namespace XNWebEngine.JsonBase
{
public class AESJavaASPDotNet
{
/// <summary>AES加密</summary>
/// <param name="text">明文</param>
/// <param name="key">密钥,长度为16的字符串</param>
/// <param name="iv">偏移量,长度为16的字符串</param>
/// <returns>密文</returns>
public static string EncodeAES(string text, string key, string iv)
{
RijndaelManaged rijndaelCipher = new RijndaelManaged();
rijndaelCipher.Mode = CipherMode.CBC;
rijndaelCipher.Padding = PaddingMode.Zeros;
rijndaelCipher.KeySize = 128;
rijndaelCipher.BlockSize = 128;
byte[] pwdBytes = System.Text.Encoding.UTF8.GetBytes(key);
byte[] keyBytes = new byte[16];
int len = pwdBytes.Length;
if (len > keyBytes.Length)
len = keyBytes.Length;
System.Array.Copy(pwdBytes, keyBytes, len);
rijndaelCipher.Key = keyBytes;
rijndaelCipher.IV = Encoding.UTF8.GetBytes(iv);
ICryptoTransform transform = rijndaelCipher.CreateEncryptor();
byte[] plainText = Encoding.UTF8.GetBytes(text);
byte[] cipherBytes = transform.TransformFinalBlock(plainText, 0, plainText.Length);
return Convert.ToBase64String(cipherBytes);
}
/// <summary>AES解密</summary>
/// <param name="text">密文</param>
/// <param name="key">密钥,长度为16的字符串</param>
/// <param name="iv">偏移量,长度为16的字符串</param>
/// <returns>明文</returns>
public static string DecodeAES(string text, string key, string iv)
{
RijndaelManaged rijndaelCipher = new RijndaelManaged();
rijndaelCipher.Mode = CipherMode.CBC;
rijndaelCipher.Padding = PaddingMode.Zeros;
rijndaelCipher.KeySize = 128;
rijndaelCipher.BlockSize = 128;
byte[] encryptedData = Convert.FromBase64String(text);
byte[] pwdBytes = System.Text.Encoding.UTF8.GetBytes(key);
byte[] keyBytes = new byte[16];
int len = pwdBytes.Length;
if (len > keyBytes.Length)
len = keyBytes.Length;
System.Array.Copy(pwdBytes, keyBytes, len);
rijndaelCipher.Key = keyBytes;
rijndaelCipher.IV = Encoding.UTF8.GetBytes(iv);
ICryptoTransform transform = rijndaelCipher.CreateDecryptor();
byte[] plainText = transform.TransformFinalBlock(encryptedData, 0, encryptedData.Length);
return Encoding.UTF8.GetString(plainText);
}
}
}
namespace XNWebEngine.JsonBase
{
public class RESJavaHelper
{
/// <summary>
/// 生成公钥和私钥对
/// </summary>
public static void GeneratePublicAndPrivateKeyInfo()
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
using (StreamWriter writer = new StreamWriter("PrivateKey.xml")) //这个文件要保密...
{
string privateKey = rsa.ToXmlString(true);
writer.WriteLine(privateKey);
}
using (StreamWriter writer = new StreamWriter("PublicKey.xml"))
{
string publicKey = rsa.ToXmlString(false);
writer.WriteLine(publicKey);
}
}
public static void GeneratePublicAndPrivateKeyInfo(out string privateKey, out string publicKey)
{
privateKey = "";
publicKey = "";
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
privateKey = rsa.ToXmlString(true);
publicKey = rsa.ToXmlString(false);
}
/// <summary>
/// 用私钥给数据进行RSA加密
/// </summary>
/// <param name="xmlPrivateKey"> 私钥(XML格式字符串)</param>
/// <param name="strEncryptString">要加密的数据</param>
/// <returns> 加密后的数据 </returns>
public static string PrivateKeyEncrypt(string xmlPrivateKey, string strEncryptString)
{
//加载私钥
RSACryptoServiceProvider privateRsa = new RSACryptoServiceProvider();
privateRsa.FromXmlString(ReadFile(xmlPrivateKey));
//转换密钥
AsymmetricCipherKeyPair keyPair = DotNetUtilities.GetKeyPair(privateRsa);
IBufferedCipher c = CipherUtilities.GetCipher("RSA/ECB/PKCS1Padding"); //使用RSA/ECB/PKCS1Padding格式
//第一个参数为true表示加密,为false表示解密;第二个参数表示密钥
c.Init(true, keyPair.Private);
byte[] dataToEncrypt = Encoding.UTF8.GetBytes(strEncryptString);
#region 分段加密
int bufferSize = (privateRsa.KeySize / 8) - 11;
byte[] buffer = new byte[bufferSize];
byte[] outBytes = null;
//分段加密
using (MemoryStream input = new MemoryStream(dataToEncrypt))
using (MemoryStream ouput = new MemoryStream())
{
while (true)
{
int readLine = input.Read(buffer, 0, bufferSize);
if (readLine <= 0)
{
break;
}
byte[] temp = new byte[readLine];
Array.Copy(buffer, 0, temp, 0, readLine);
byte[] encrypt = c.DoFinal(temp);
ouput.Write(encrypt, 0, encrypt.Length);
}
outBytes = ouput.ToArray();
}
#endregion
//byte[] outBytes = c.DoFinal(DataToEncrypt);//加密
string strBase64 = Convert.ToBase64String(outBytes);
return strBase64;
}
/// <summary>
/// 用公钥给数据进行RSA解密
/// </summary>
/// <param name="xmlPublicKey"> 公钥(XML格式字符串) </param>
/// <param name="strDecryptString"> 要解密数据 </param>
/// <returns> 解密后的数据 </returns>
public static string PublicKeyDecrypt(string xmlPublicKey, string strDecryptString)
{
//加载公钥
RSACryptoServiceProvider publicRsa = new RSACryptoServiceProvider();
publicRsa.FromXmlString(ReadFile(xmlPublicKey));
RSAParameters rp = publicRsa.ExportParameters(false);
//转换密钥
AsymmetricKeyParameter pbk = DotNetUtilities.GetRsaPublicKey(rp);
IBufferedCipher c = CipherUtilities.GetCipher("RSA/ECB/PKCS1Padding");
//第一个参数为true表示加密,为false表示解密;第二个参数表示密钥
c.Init(false, pbk);
byte[] outBytes = null;
byte[] dataToDecrypt = Convert.FromBase64String(strDecryptString);
#region 分段解密
int keySize = publicRsa.KeySize / 8;
byte[] buffer = new byte[keySize];
using (MemoryStream input = new MemoryStream(dataToDecrypt))
using (MemoryStream output = new MemoryStream())
{
while (true)
{
int readLine = input.Read(buffer, 0, keySize);
if (readLine <= 0)
{
break;
}
byte[] temp = new byte[readLine];
Array.Copy(buffer, 0, temp, 0, readLine);
byte[] decrypt = c.DoFinal(temp);
output.Write(decrypt, 0, decrypt.Length);
}
outBytes = output.ToArray();
}
#endregion
//byte[] outBytes = c.DoFinal(DataToDecrypt);//解密
string strDec = Encoding.UTF8.GetString(outBytes);
return strDec;
}
/// <summary>
/// 使用公钥加密,分段加密
/// </summary>
/// <param name="content"></param>
/// <param name="privateKeyPath"></param>
/// <returns></returns>
public static string EncrytByPublic(string publicKeyPath, string strEncryptString)
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(ReadFile(publicKeyPath));
byte[] originalData = Encoding.UTF8.GetBytes(strEncryptString);
if (originalData == null || originalData.Length <= 0)
{
throw new NotSupportedException();
}
if (rsa == null)
{
throw new ArgumentNullException();
}
byte[] encryContent = null;
#region 分段加密
int bufferSize = (rsa.KeySize / 8) - 11;
byte[] buffer = new byte[bufferSize];
//分段加密
using (MemoryStream input = new MemoryStream(originalData))
using (MemoryStream ouput = new MemoryStream())
{
while (true)
{
int readLine = input.Read(buffer, 0, bufferSize);
if (readLine <= 0)
{
break;
}
byte[] temp = new byte[readLine];
Array.Copy(buffer, 0, temp, 0, readLine);
byte[] encrypt = rsa.Encrypt(temp, false);
ouput.Write(encrypt, 0, encrypt.Length);
}
encryContent = ouput.ToArray();
}
#endregion
return Convert.ToBase64String(encryContent);
}
/// <summary>
/// 通过私钥解密,分段解密
/// </summary>
/// <param name="content"></param>
/// <param name="privateKeyPath"></param>
/// <returns></returns>
public static string DecryptByPrivate(string privateKeyPath, string strDecryptString)
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(ReadFile(privateKeyPath));
byte[] encryptData = Convert.FromBase64String(strDecryptString);
//byte[] dencryContent = rsa.Decrypt(encryptData, false);
byte[] dencryContent = null;
#region 分段解密
if (encryptData == null || encryptData.Length <= 0)
{
throw new NotSupportedException();
}
int keySize = rsa.KeySize / 8;
byte[] buffer = new byte[keySize];
using (MemoryStream input = new MemoryStream(encryptData))
using (MemoryStream output = new MemoryStream())
{
while (true)
{
int readLine = input.Read(buffer, 0, keySize);
if (readLine <= 0)
{
break;
}
byte[] temp = new byte[readLine];
Array.Copy(buffer, 0, temp, 0, readLine);
byte[] decrypt = rsa.Decrypt(temp, false);
output.Write(decrypt, 0, decrypt.Length);
}
dencryContent = output.ToArray();
}
#endregion
return Encoding.UTF8.GetString(dencryContent);
}
public static string PrivateKeyStringEncrypt(string xmlPrivateKey, string strEncryptString)
{
//加载私钥
RSACryptoServiceProvider privateRsa = new RSACryptoServiceProvider();
privateRsa.FromXmlString(xmlPrivateKey);
//转换密钥
AsymmetricCipherKeyPair keyPair = DotNetUtilities.GetKeyPair(privateRsa);
IBufferedCipher c = CipherUtilities.GetCipher("RSA/ECB/PKCS1Padding"); //使用RSA/ECB/PKCS1Padding格式
//第一个参数为true表示加密,为false表示解密;第二个参数表示密钥
c.Init(true, keyPair.Private);
byte[] dataToEncrypt = Encoding.UTF8.GetBytes(strEncryptString);
#region 分段加密
int bufferSize = (privateRsa.KeySize / 8) - 11;
byte[] buffer = new byte[bufferSize];
byte[] outBytes = null;
//分段加密
using (MemoryStream input = new MemoryStream(dataToEncrypt))
using (MemoryStream ouput = new MemoryStream())
{
while (true)
{
int readLine = input.Read(buffer, 0, bufferSize);
if (readLine <= 0)
{
break;
}
byte[] temp = new byte[readLine];
Array.Copy(buffer, 0, temp, 0, readLine);
byte[] encrypt = c.DoFinal(temp);
ouput.Write(encrypt, 0, encrypt.Length);
}
outBytes = ouput.ToArray();
}
#endregion
//byte[] outBytes = c.DoFinal(DataToEncrypt);//加密
string strBase64 = Convert.ToBase64String(outBytes);
return strBase64;
}
/// <summary>
/// 用公钥给数据进行RSA解密
/// </summary>
/// <param name="xmlPublicKey"> 公钥(XML格式字符串) </param>
/// <param name="strDecryptString"> 要解密数据 </param>
/// <returns> 解密后的数据 </returns>
public static string PublicKeyStringDecrypt(string xmlPublicKey, string strDecryptString)
{
//加载公钥
RSACryptoServiceProvider publicRsa = new RSACryptoServiceProvider();
publicRsa.FromXmlString(xmlPublicKey);
RSAParameters rp = publicRsa.ExportParameters(false);
//转换密钥
AsymmetricKeyParameter pbk = DotNetUtilities.GetRsaPublicKey(rp);
IBufferedCipher c = CipherUtilities.GetCipher("RSA/ECB/PKCS1Padding");
//第一个参数为true表示加密,为false表示解密;第二个参数表示密钥
c.Init(false, pbk);
byte[] outBytes = null;
byte[] dataToDecrypt = Convert.FromBase64String(strDecryptString);
#region 分段解密
int keySize = publicRsa.KeySize / 8;
byte[] buffer = new byte[keySize];
using (MemoryStream input = new MemoryStream(dataToDecrypt))
using (MemoryStream output = new MemoryStream())
{
while (true)
{
int readLine = input.Read(buffer, 0, keySize);
if (readLine <= 0)
{
break;
}
byte[] temp = new byte[readLine];
Array.Copy(buffer, 0, temp, 0, readLine);
byte[] decrypt = c.DoFinal(temp);
output.Write(decrypt, 0, decrypt.Length);
}
outBytes = output.ToArray();
}
#endregion
//byte[] outBytes = c.DoFinal(DataToDecrypt);//解密
string strDec = Encoding.UTF8.GetString(outBytes);
return strDec;
}
/// <summary>
/// 使用公钥加密,分段加密
/// </summary>
/// <param name="content"></param>
/// <param name="privateKeyPath"></param>
/// <returns></returns>
public static string EncrytByPublicString(string publicKeyPath, string strEncryptString)
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(publicKeyPath);
byte[] originalData = Encoding.UTF8.GetBytes(strEncryptString);
if (originalData == null || originalData.Length <= 0)
{
throw new NotSupportedException();
}
if (rsa == null)
{
throw new ArgumentNullException();
}
byte[] encryContent = null;
#region 分段加密
int bufferSize = (rsa.KeySize / 8) - 11;
byte[] buffer = new byte[bufferSize];
//分段加密
using (MemoryStream input = new MemoryStream(originalData))
using (MemoryStream ouput = new MemoryStream())
{
while (true)
{
int readLine = input.Read(buffer, 0, bufferSize);
if (readLine <= 0)
{
break;
}
byte[] temp = new byte[readLine];
Array.Copy(buffer, 0, temp, 0, readLine);
byte[] encrypt = rsa.Encrypt(temp, false);
ouput.Write(encrypt, 0, encrypt.Length);
}
encryContent = ouput.ToArray();
}
#endregion
return Convert.ToBase64String(encryContent);
}
/// <summary>
/// 通过私钥解密,分段解密
/// </summary>
/// <param name="content"></param>
/// <param name="privateKeyPath"></param>
/// <returns></returns>
public static string DecryptByPrivateString(string privateKeyPath, string strDecryptString)
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(privateKeyPath);
byte[] encryptData = Convert.FromBase64String(strDecryptString);
//byte[] dencryContent = rsa.Decrypt(encryptData, false);
byte[] dencryContent = null;
#region 分段解密
if (encryptData == null || encryptData.Length <= 0)
{
throw new NotSupportedException();
}
int keySize = rsa.KeySize / 8;
byte[] buffer = new byte[keySize];
using (MemoryStream input = new MemoryStream(encryptData))
using (MemoryStream output = new MemoryStream())
{
while (true)
{
int readLine = input.Read(buffer, 0, keySize);
if (readLine <= 0)
{
break;
}
byte[] temp = new byte[readLine];
Array.Copy(buffer, 0, temp, 0, readLine);
byte[] decrypt = rsa.Decrypt(temp, false);
output.Write(decrypt, 0, decrypt.Length);
}
dencryContent = output.ToArray();
}
#endregion
return Encoding.UTF8.GetString(dencryContent);
}
/// <summary>
/// 读取文件
/// </summary>
/// <param name="filePath"></param>
/// <returns></returns>
public static string ReadFile(string filePath)
{
string content = "";
if (File.Exists(filePath))
{
content = File.ReadAllText(filePath);
byte[] mybyte = Encoding.UTF8.GetBytes(content);
content = Encoding.UTF8.GetString(mybyte);
}
return content;
}
/// <summary>
/// 将私钥转换成java所用的私钥字符串
/// </summary>
/// <param name="privateKeyPath">私钥文件路径</param>
/// <returns></returns>
public static string RSAPrivateKeyDotNet2Java(string privateKeyPath)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(ReadFile(privateKeyPath));
Org.BouncyCastle.Math.BigInteger m = new Org.BouncyCastle.Math.BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Modulus")[0].InnerText));
Org.BouncyCastle.Math.BigInteger exp = new Org.BouncyCastle.Math.BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Exponent")[0].InnerText));
Org.BouncyCastle.Math.BigInteger d = new Org.BouncyCastle.Math. BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("D")[0].InnerText));
Org.BouncyCastle.Math.BigInteger p = new Org.BouncyCastle.Math.BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("P")[0].InnerText));
Org.BouncyCastle.Math.BigInteger q = new Org.BouncyCastle.Math.BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Q")[0].InnerText));
Org.BouncyCastle.Math.BigInteger dp = new Org.BouncyCastle.Math.BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("DP")[0].InnerText));
Org.BouncyCastle.Math.BigInteger dq = new Org.BouncyCastle.Math.BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("DQ")[0].InnerText));
Org.BouncyCastle.Math.BigInteger qinv = new Org.BouncyCastle.Math.BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("InverseQ")[0].InnerText));
RsaPrivateCrtKeyParameters privateKeyParam = new RsaPrivateCrtKeyParameters(m, exp, d, p, q, dp, dq, qinv);
PrivateKeyInfo privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(privateKeyParam);
byte[] serializedPrivateBytes = privateKeyInfo.ToAsn1Object().GetEncoded();
return Convert.ToBase64String(serializedPrivateBytes);
}
/// <summary>
/// 将公钥转换成java所用的公钥字符串
/// </summary>
/// <param name="publicKeyPath">公钥路径</param>
/// <returns></returns>
public static string RSAPublicKeyDotNet2Java(string publicKeyPath)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(ReadFile(publicKeyPath));
Org.BouncyCastle.Math.BigInteger m = new Org.BouncyCastle.Math.BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Modulus")[0].InnerText));
Org.BouncyCastle.Math.BigInteger p = new Org.BouncyCastle.Math.BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Exponent")[0].InnerText));
RsaKeyParameters pub = new RsaKeyParameters(false, m, p);
SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(pub);
byte[] serializedPublicBytes = publicKeyInfo.ToAsn1Object().GetDerEncoded();
return Convert.ToBase64String(serializedPublicBytes);
}
public static string RSAPrivateKeyStringDotNet2Java(string privateKeyString)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(privateKeyString);
Org.BouncyCastle.Math.BigInteger m = new Org.BouncyCastle.Math.BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Modulus")[0].InnerText));
Org.BouncyCastle.Math.BigInteger exp = new Org.BouncyCastle.Math.BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Exponent")[0].InnerText));
Org.BouncyCastle.Math.BigInteger d = new Org.BouncyCastle.Math.BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("D")[0].InnerText));
Org.BouncyCastle.Math.BigInteger p = new Org.BouncyCastle.Math.BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("P")[0].InnerText));
Org.BouncyCastle.Math.BigInteger q = new Org.BouncyCastle.Math.BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Q")[0].InnerText));
Org.BouncyCastle.Math.BigInteger dp = new Org.BouncyCastle.Math.BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("DP")[0].InnerText));
Org.BouncyCastle.Math.BigInteger dq = new Org.BouncyCastle.Math.BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("DQ")[0].InnerText));
Org.BouncyCastle.Math.BigInteger qinv = new Org.BouncyCastle.Math.BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("InverseQ")[0].InnerText));
RsaPrivateCrtKeyParameters privateKeyParam = new RsaPrivateCrtKeyParameters(m, exp, d, p, q, dp, dq, qinv);
PrivateKeyInfo privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(privateKeyParam);
byte[] serializedPrivateBytes = privateKeyInfo.ToAsn1Object().GetEncoded();
return Convert.ToBase64String(serializedPrivateBytes);
}
/// <summary>
/// 将公钥转换成java所用的公钥字符串
/// </summary>
/// <param name="publicKeyPath">公钥路径</param>
/// <returns></returns>
public static string RSAPublicKeyStringDotNet2Java(string publicKeyPath)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(publicKeyPath);
Org.BouncyCastle.Math.BigInteger m = new Org.BouncyCastle.Math.BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Modulus")[0].InnerText));
Org.BouncyCastle.Math.BigInteger p = new Org.BouncyCastle.Math.BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Exponent")[0].InnerText));
RsaKeyParameters pub = new RsaKeyParameters(false, m, p);
SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(pub);
byte[] serializedPublicBytes = publicKeyInfo.ToAsn1Object().GetDerEncoded();
return Convert.ToBase64String(serializedPublicBytes);
}
}
}
//Go的对称加密算法
// HelloAES project main.go
package main
import (
"fmt"
//"net/http"
// "io/ioutil"
//"encoding/json"
//"strconv"
"bytes"
"crypto/aes"
"crypto/cipher"
//"crypto/rand"
//"crypto/rsa"
//"crypto/sha1"
//"crypto/sha256"
// "time"
//"crypto/rand"
"encoding/base64"
//"io"
"github.com/Lyafei/go-rsa"
)
func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}
func PKCS5UnPadding(origData []byte) []byte {
length := len(origData)
unpadding := int(origData[length-1])
return origData[:(length - unpadding)]
}
//使用PKCS7进行填充
func PKCS7Padding(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}
func PKCS7UnPadding(origData []byte) []byte {
length := len(origData)
unpadding := int(origData[length-1])
return origData[:(length - unpadding)]
}
func ZerosPadding(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext)%blockSize
fmt.Println("padding", padding)
padtext := bytes.Repeat([]byte{byte(0)}, padding)
return append(ciphertext, padtext...)
}
func ZerosUnPadding(origData []byte) []byte {
length := len(origData)
unpadding := int(origData[length-1])
return origData[:(length - unpadding)]
}
//aes加密,填充秘钥key的16位,24,32分别对应AES-128, AES-192, or AES-256.
func AesCBCEncrypt(rawData, key []byte, iv []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
//填充原文
blockSize := block.BlockSize()
//fmt.Println(blockSize)
//rawData = PKCS5Padding(rawData, blockSize)
rawData = ZerosPadding(rawData, blockSize)
//初始向量IV必须是唯一,但不需要保密
cipherText := make([]byte, blockSize+len(rawData))
//block大小 16
/*
iv := cipherText[:blockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
*/
//block大小和初始向量大小一定要一致
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(cipherText[blockSize:], rawData)
return cipherText, nil
}
func AesCBCDncrypt(encryptData, key []byte, iv []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
blockSize := block.BlockSize()
if len(encryptData) < blockSize {
panic("ciphertext too short")
}
/*
iv := encryptData[:blockSize]
*/
encryptData = encryptData[blockSize:]
fmt.Println("encryptData=", encryptData)
fmt.Println(len(encryptData) % blockSize)
// CBC mode always works in whole blocks.
if len(encryptData)%blockSize != 0 {
panic("ciphertext is not a multiple of the block size")
}
mode := cipher.NewCBCDecrypter(block, iv)
// CryptBlocks can work in-place if the two arguments are the same.
mode.CryptBlocks(encryptData, encryptData)
//解填充
//encryptData = PKCS5UnPadding(encryptData)
encryptData = ZerosUnPadding(encryptData)
return encryptData, nil
}
func Encrypt(rawData, key []byte, iv []byte) (string, error) {
data, err := AesCBCEncrypt(rawData, key, iv)
if err != nil {
return "", err
}
fmt.Println("data", data)
data = data[16:]
fmt.Println("outdata", data)
//return base64.EncodeToString(data), nil
return base64.StdEncoding.EncodeToString(data), nil
}
func Dncrypt(rawData string, key []byte, iv []byte) (string, error) {
data, err := base64.StdEncoding.DecodeString(rawData)
fmt.Println("dn data", data)
if err != nil {
return "", err
}
zeroArray := [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
data = append(zeroArray[:], data...)
dnData, err := AesCBCDncrypt(data, key, iv)
if err != nil {
return "", err
}
return string(dnData), nil //
}
func main() {
fmt.Println("Hello World!")
var data []byte = []byte("xn忠魂{:程序员}")
outJMData, _ := Encrypt(data, []byte("aaabbbcccdddeeef"), []byte("1234567890abcdef"))
fmt.Println(outJMData)
outData, _ := Dncrypt(outJMData, []byte("aaabbbcccdddeeef"), []byte("1234567890abcdef"))
fmt.Println(outData)
//m_Data := make(map[string]interface{})
publicKeyString := "-----BEGIN Public key-----\r\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDVTy+1uRxJeWtkPAm/y7CSix0LS148IeU4NXPbR8DEiT6m26wz9OYR9/Aj2Z64ncQBytsQlHUI5opmRFtkDGqgfKadhG0GcAQMRCH/wNCFKdJX20TAdHtJ1jTzQb/vrd0EszPR247Z5jeQMMGtyQbZO9xvDL4jOAqur4dCigFLhQIDAQAB\r\n-----END Public key-----"
privateKeyString := "-----BEGIN Private key-----\r\nMIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBANVPL7W5HEl5a2Q8Cb/LsJKLHQtLXjwh5Tg1c9tHwMSJPqbbrDP05hH38CPZnridxAHK2xCUdQjmimZEW2QMaqB8pp2EbQZwBAxEIf/A0IUp0lfbRMB0e0nWNPNBv++t3QSzM9HbjtnmN5Awwa3JBtk73G8MviM4Cq6vh0KKAUuFAgMBAAECgYACpWnVGkfEjZIMe0Yvr+ov1zP0COpRWqZKTTdzt+8nQQCa90yqlFYqUOYUu8VhSuu8jfSrvvu4sYtz+1Ma6aCE+VWBuXIAEBI9LsE78GNKyYTJ72uEt0VEMSRmyEMbspvMMsbQFMA9zL1qWC14eNEAghlYUk5MbeAykji6aWnnAQJBAP3z2k8+sZx+MDA05nvP41lcqDsdLfl7TtARsTm8e73DLMjdM7S37z2yoGJ+bv13p2rftgIHUTiXBHKqDmQ0I8UCQQDXB3Kc3T8Tqf3FtDOGHElkRf7pEIr9XfwnpLLdieuuw6BQq/71TSOoc5dzonNKTtsxEqHZtkYihXj752U5ikTBAkB0odEqwf1qhR32leUhCfo9aWuuMpmR0gsBTo7ZmHIwVfo0ijscDbnn2SkF81FgQdr3H6WEyv2Hgvw8+VNAvB2NAkAoW1F7d1q7ShBC5ss0xGJR24E4JM6xNs54ckTPp28AYd7YxS8Ywt2KZAdswHR64cnpr+GIhtkq6XoHbSpmXjkBAkEA8HP1XnU7F69JjSi0GJZK2I03LiU6K9QIZH5NcdDaxAwvWrlDjT0Im2uiwcRXCyaH/57zJ4iuIqfJmLG6Df5f4g==\r\n-----END Private key-----"
str := "中华"
prienctypt, err := gorsa.PriKeyEncrypt(str, privateKeyString)
if err != nil {
fmt.Println(err)
return
}
//fmt.Println(publicKeyString)
fmt.Println("私钥加密后:", prienctypt)
pubdecrypt, err := gorsa.PublicDecrypt(prienctypt, publicKeyString)
if err != nil {
return
}
fmt.Println("公钥解密后:", string(pubdecrypt))
pubenctypt, err := gorsa.PublicEncrypt(str, publicKeyString)
if err != nil {
fmt.Println(err)
return
}
fmt.Println("公钥加密后:", pubenctypt)
pridecrypt, err := gorsa.PriKeyDecrypt(pubenctypt, privateKeyString)
if err != nil {
return
}
fmt.Println("私钥解密后:", string(pridecrypt))
}
关于Nginx设置端口号,在Asp.net 获取不到的,解决办法
不知道你有没有遇到过这样的问题,网站访客多起来后,心里很是高兴,加上了Nginx反向代理,出问题了
原来是这么写的:
Request.Url.ToString()
输出是这样的:
http://www.zhyj2013.com:6038/Default/Index
平白无故多出个端口号
Nginx是这样配置的
server {
listen 80;
server_name www.zhyj2013.com;
location / {
root html;
index index.html index.htm;
proxy_pass http://localhost:6038;
proxy_set_header Host $http_host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
大家都是这样配置的,没有什么问题,网上也找不到Asp.Net解决问题的方法,最后我翻看了System.Web.dll 发现他读取appSetting节点 aspnet:UseHostHeaderForRequestUrl 子节点,于是,在项目的WebConfig加上配置,好了
<appSettings>
<add key="aspnet:UseHostHeaderForRequestUrl" value="true"/>
</appSettings>
再刷新
输出是这样的:
http://www.zhyj2013.com/Default/Index
至此,问题解决。
从业十多年,竟然不知道这样的问题,还是涉猎不够。