博客主页

解决黑苹果Monterey蓝牙睡眠后不工作问题

自Monterey(macOS 12.x)以来,博通BCM94360的网卡蓝牙模块可能会出现问题,具体表现为睡眠唤醒后,蓝牙会出现睡死的情况,即需要进入系统把蓝牙关了重新打开才能正常工作。

苹果切换到Apple silicon后,貌似Opencore现在对Hackintosh也没那么上心了,蓝牙问题已经挺久。现在曲线救国的办法是在睡眠之前把蓝牙关闭,睡醒后再打开,这样会省事很多。我们当然不会手动去做这个事,mac下刚好有个app叫sleepwatcher,可以监控睡眠和唤醒。

准备工作

  1. 下载sleepwatcher

    推荐官网直接下载,地址: https://www.bernhard-baehr.de/。(地址可能需要翻墙才能访问)

  2. 安装blueutil

    blueutil是一个蓝牙工具,可以通过命令打开和关闭蓝牙,推荐使用homebrew下载

    brew install blueutil
    

安装sleepwatcher

首先通过终端进入sleepwatcher的文件夹,以我的为例,版本为sleepwatcher_2.2.1

cd sleepwatcher_2.2.1
sudo cp ./sleepwatcher /usr/local/sbin
sudo cp ./sleepwatcher.8 /usr/local/share/man/man8

#创建数据文件夹,这个可以自定义,如果选择不同的路径,下面的路径也必须跟着修改
mkdir ~/.sleep

Read more

恒星的演变过程

Youtube有个很有趣的频道叫Discovery With Andy,频道主题大多跟天文有关,讲的特别有趣。这期讲恒星的演变过程非常精彩,虽然这些知识可以在维基百科轻易找到,不过面对那些文字还是缺乏趣味性。

Andy的视频配乐和资料都是上乘的,这期恒星演变是我最喜欢的一期。

回想十几年前写博客时特别喜欢分享一些乱七八糟的东西,现在博客都是一些技术资料,显得有些单调。

Read more

EIP55-以太坊账户地址校验算法

以太坊账户地址是一个40字符的hex string,细心的朋友可能会发现账户地址有些字母包含了大写字母和小写字母,但实际交易时,用小些地址也可以正常执行操作。

查了一下资料,发现原来包含大写字母的是经过了校验和(checksum)的地址

  • 0x7cb57b5a97eabe94205c07890be4c1ad31e486a8
  • 0x7cB57B5A97eAbe94205C07890BE4c1aD31E486A8

上面两个地址的区别是,前者不包含校验和(checksum),后者是包含校验和的地址。这个校验和有什么作用呢?因为以太坊地址本身不包含校验信息,一旦用户输入错误,没有一种机制校验,该交易将会永远丢失。

为了解决上面的问题,2016年有人在github提了一个Improvement Proposal《Yet another cool checksum address encoding》,用一种向后兼容的校验和算法对账户地址进行checksum。这种算法得满足下面条件:

  • 向下兼容
  • 保持账户地址的长度和信息都不发生变化
  • 足够低的碰撞概率

上面提到的proposal提出了一种算法来解决这个问题,该算法原文描述如下:

In English, convert the address to hex, but if the ith digit is a letter (ie. it’s one of abcdef) print it in uppercase if the ith bit of the hash of the address (in binary form) is 1 otherwise print it in lowercase.

上面描述的意思需要结合代码看才更加清晰,我用自己的语言描述如下:

先把账户地址经过digist再转为hex string,然后遍历用户原本的地址,如果hex string和原地址对应位置的字符是一个字母时,把原地址的字符转为大写字符,否则是一个小些字符。

该算法最终被采纳为以太坊的标准,EIP-55。EIP-55的实现原理实际上非常简单,代码甚至都不到10行,非常简洁。下面是EIP55的JS实现,感受一下极致简洁的代码带来的美感。

const createKeccakHash = require('keccak')

function toChecksumAddress (address) {
  address = address.toLowerCase().replace('0x', '')
  var hash = createKeccakHash('keccak256').update(address).digest('hex')
  var ret = '0x'

  for (var i = 0; i < address.length; i++) {
    if (parseInt(hash[i], 16) > 7) {
      ret += address[i].toUpperCase()
    } else {
      ret += address[i]
    }
  }

  return ret
}

参考资料:

Vitalik Buterin, Alex Van de Sande, “EIP-55: Mixed-case checksum address encoding,” Ethereum Improvement Proposals, no. 55, January 2016. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-55.
Ethereum Address Has Uppercase and Lowercase Letters

Read more

shadowsocks rc4-md5算法介绍

shadowsocks协议早期使用RC4加密算法用于加密数据,不过因为每次数据都适用同一个密钥流加密,存在很大的安全隐患,后面更新了RC4-MD5算法。

即便关于RC4-MD5协议的资料很难找到,而且RC4-MD5算法现在也不在安全,但还是有必要介绍一遍,因为它简单,很便于理解,在后期也会展示RC4算法的缺陷。

RC4-MD5本质上还是RC4对数据进行加密。MD5的意思是对key进行MD5运算,得到RC4的key,最终会被RC4算法用于生成密钥流。简单来说,用户的密码会经过下面步骤转换为RC4的keystream

  1. k1 = toBytes(password)
  2. k2 = ssKey(k1)
  3. rc4-md5-key = md5(toBytes(k2,iv))

Read more

手把手使用Java实现一个Socks5代理

1. 前言

上一篇文章介绍了socks5协议的工作过程和协议的细节,通过上一篇文章我们可以认识到socks5协议主要有3个阶段,分别为: 协商、请求,转发(Relay)。本文将手把手使用Java语言实现一个简单的socks5代理

特别提醒: 本文目的仅作为加深socks5协议理解,其中的代码并不是严谨的代码,也没考虑其他的情况。在实际的开发过程中,需要考虑更多的意外情况。

上一篇文章中有一张时序图展示了socks5的大概工作过程,本文将使用Java把这些过程一一实现。

~replace~/assets/images/socks5/client-socks5_f.jpg

Read more

理解socks5协议的工作过程和协议细节

1. 前言

本位将由浅入深带大家详细了解socks5协议。文章首先会对socks协议进行简单介绍,接着会介绍socks5协议的使用场景,然后介绍它的工作工程,最后介绍协议的细节(握手、数据转发)。

2. 协议介绍

2.1 什么是socks协议

啥是socks协议呢? 这里贴一段维基百科对它的定义

SOCKS is an Internet protocol that exchanges network packets between a client and server through a proxy server

大概的意思是: socks是一种互联网协议,它通过一个代理服务器在客户端和服务端之间交换网络数据。简单来说,它就是一种代理协议,扮演一个中间人的角色,在客户端和目标主机之间转发数据。

~replace~/assets/images/socks5/socks5_01.jpeg

socks协议位于OSI模型中的第五层,即会话层(Session Layer)。

Read more

理解Java中的Bridge Method

bridge method又叫synthetic method,它是由Java编译器自动生成的一个合成方法,这个方法不会出现在源码中,也不能显式调用。我们先通过一个例子对bridge method有一个感性的认识。

// Code 1-1
class Animal {
  public Animal getAnimal() {
    return new Animal();
  }
}

class Dog extends Animal {
  public Dog getAnimal() {
    return new Dog();
  }
}

上面定义了Animal和Dog两个类,Dog是Animal的subclass,且Dog类override了Animal的getAnimal方法。如果你现在尝试去编译Dog,很大概率是可以直接通过编译,不过当我们尝试使用JDK 1.4以下版本编译,就是另外一回事了。

javac org/wiyi/bridge/Dog.java
org/wiyi/bridge/Dog.java:6: getAnimal() in org.wiyi.bridge.Dog cannot override g
etAnimal() in org.wiyi.bridge.Animal; attempting to use incompatible return type

found   : org.wiyi.bridge.Dog
required: org.wiyi.bridge.Animal
  public Dog getAnimal() {
             ^
1 error

Read more

深入理解面向对象中的多态

多态

多态并非是计算机科学领域的专有名词,在其他领域比如生物领域也有使用。比如猫科动物中,有狮子、老虎、豹、山猫等,其中雄性狮子会有很长的胡须等,都是现实生活中的多态。

基于上面的描述,我们不难理解计算机领域中的”多态”,实际上它也是对现实世界的一种抽象。在现实中,猫可以代指小猫咪、老虎、狮子等动物,具体到计算机领域的抽象,可以用下面语法表达:

Cat cat = new Tiger();

用一个符号来表现同一种类型的不同形态,这就是多态。相信所有Java程序员对上面语法早已烂熟于心,这种语法属于多态中的一个分支,叫Subtyping(也叫subtype polymorphism,子类型多态)。

多态是类型系统中一个重要的概念,在Java语言中,实现了3种类型的多态,分别为:

  • Ad hoc polymorphism (特殊的多态)
  • subtype polymorphism (子类型多态)
  • Parametric polymorphism (参数化多态)

本文将详细介绍这3种类型的多态,进一步加深对多态的理解。

Read more