分类 默认分类 下的文章

在 Debian 13 上让 Intel IPU6 摄像头工作

Dell Latitude 7450 = Intel Meteor Lake + Hynix HI556 sensor + IPU6 ISP,通过 USB-IO Bridge 连接。
Debian 13 + Linux 6.12(默认)+ mainline IPU6 子系统 + 浏览器 = 各种坑全踩齐。
本文记录把这台机器的摄像头从"灯不亮、/dev/video0 没图"做到"Teams/Edge/Firefox/飞书全部可用"的完整过程。

整套修复跨越内核、固件、ACPI、用户态 HAL、GStreamer、v4l2loopback、PipeWire、Chromium 过滤规则等 11 个层级。一个组件都不能少。


硬件 / 软件起点

  • 机器:Dell Latitude 7450(Intel Meteor Lake,2024 款)
  • 传感器:Hynix HI556(前置摄像头)+ OV2740(IR 红外,本文不涉及)
  • 桥接:通过 USB-IO Bridge(ACPI ID INTC10D1/D2/D3,Dell 变种)暴露 GPIO/I2C/SPI
  • ISP:Intel IPU6 PCIe 设备 0000:00:05.0
  • 操作系统:Debian 13 Trixie,默认内核 6.12.90+deb13
  • 桌面:KDE Plasma(X11)

启动后症状:

  • lspci 看到 Intel Corporation Meteor Lake IPU,模块 intel_ipu6_isys 已加载
  • /dev/video0 到 /dev/video47 都有,但全是 IPU6 内部 isys media graph 节点
  • 任何应用打开都拿不到画面,摄像头隐私灯也不亮
  • dmesg | grep int3472 死循环报错:cannot find GPIO chip INTC10D1:00, deferring

1. 诊断:摄像头链路在哪一环断了

lspci -k | grep -A2 Multimedia        # IPU6 PCIe 设备
lsmod | grep -E 'ipu6|hi556'          # 内核模块状态
ls /dev/video* /dev/media*            # V4L2 设备节点
cam --list 2>&1                       # libcamera 视角
sudo dmesg | grep -iE 'int3472|hi556|ipu6|INTC10' | head -50

关键报错:

int3472-discrete INT3472:01: GPIO type 0x12 unknown; the sensor may not work
int3472-discrete INT3472:01: cannot find GPIO chip INTC10D1:00, deferring

意思是 sensor 的电源/复位 GPIO 是经 USB-IO Bridge 提供的,但 mainline 内核 usbio 驱动没匹配到 Dell 的 ACPI ID INTC10D1。整条链直接卡在底层。


2. 用户态栈:bins + HAL + icamerasrc

Intel 在 Linux 上的 IPU6 用户态是闭源 blob + 开源胶水:

先装这三个:

sudo apt install -y \
  build-essential meson ninja-build cmake pkg-config git ca-certificates \
  autoconf automake libtool autoconf-archive \
  python3-yaml python3-ply python3-jinja2 \
  libdrm-dev libyaml-dev libssl-dev libgnutls28-dev libudev-dev libsystemd-dev \
  libpython3-dev libevent-dev libtiff-dev libjpeg-dev \
  libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \
  gstreamer1.0-plugins-{base,good,bad} gstreamer1.0-tools \
  v4l-utils

2.1 ipu6-camera-bins(专有 blob)

sudo mkdir -p /opt/ipu6-src && cd /opt/ipu6-src
sudo git clone --depth=1 https://github.com/intel/ipu6-camera-bins.git
cd ipu6-camera-bins
sudo mkdir -p /lib/firmware/intel/ipu /usr/lib/x86_64-linux-gnu/pkgconfig
sudo cp -rv lib/firmware/intel/ipu/*.bin /lib/firmware/intel/ipu/
# 创建无版本后缀 symlink,链接器才能找到
for libpath in lib/lib*.so.*; do
  libname=${libpath##*/}
  sudo ln -sf "$libname" "lib/${libname%.*}"
done
sudo cp -Pv lib/lib*.so* /usr/lib/x86_64-linux-gnu/
sudo cp -Pv lib/lib*.a   /usr/lib/x86_64-linux-gnu/  # 静态库也要拷!
sudo cp -rv include/* /usr/include/
sudo cp -rv lib/pkgconfig/* /usr/lib/x86_64-linux-gnu/pkgconfig/
sudo ldconfig

坑 1:.a 文件必须拷,HAL 链接 libipu6epmtl.a 静态库。

2.2 ipu6-camera-hal

cd /opt/ipu6-src
sudo git clone --depth=1 https://github.com/intel/ipu6-camera-hal.git
cd ipu6-camera-hal && sudo mkdir -p build && cd build
sudo cmake \
  -DCMAKE_BUILD_TYPE=Release \
  -DIPU_VERSIONS="ipu6epmtl" \
  -DUSE_PG_LITE_PIPE=ON \
  -DBUILD_CAMHAL_PLUGIN=ON \
  -DBUILD_CAMHAL_ADAPTOR=ON \
  -DCMAKE_INSTALL_PREFIX=/usr \
  -DCMAKE_INSTALL_LIBDIR=lib/x86_64-linux-gnu \
  ..
sudo make -j"$(nproc)" && sudo make install && sudo ldconfig

坑 2:BUILD_CAMHAL_PLUGIN=ON 才让 cmake 在 TARGET_SUFFIX 里加平台后缀(-ipu6epmtl),否则 cmake 找的是无后缀 pkgconfig(ia_imaging)而不是装上的 ia_imaging-ipu6epmtl.pc。

坑 3:BUILD_CAMHAL_ADAPTOR=ON 同时打开才生成 libcamhal.pc,icamerasrc 需要这个 pkgconfig。

2.3 icamerasrc

cd /opt/ipu6-src
sudo git clone --depth=1 -b icamerasrc_slim_api https://github.com/intel/icamerasrc.git
cd icamerasrc
sudo bash -c 'export CHROME_SLIM_CAMHAL=ON && ./autogen.sh && make -j"$(nproc)" && make install && ldconfig'

装到 /usr/lib/gstreamer-1.0/libgsticamerasrc.so(不是 Debian 默认的 multiarch 路径 /usr/lib/x86_64-linux-gnu/gstreamer-1.0/,每次用都要设 GST_PLUGIN_PATH=/usr/lib/gstreamer-1.0)。


3. IVSC 固件

Dell 7450 的摄像头通过 IVSC(Intel Visual Sensing Controller)中转,需要专门固件:

sudo apt install -t stable-backports firmware-misc-nonfree   # 不一定有 IVSC
# 一般还是要从源拉:
cd /opt/ipu6-src
sudo git clone --depth=1 https://github.com/intel/ivsc-firmware.git
sudo mkdir -p /lib/firmware/intel/ivsc
sudo cp -v ivsc-firmware/firmware/*.bin /lib/firmware/intel/ivsc/

ivsc_pkg_hi556_0.bin、ivsc_skucfg_hi556_0_1.bin、ivsc_pkg_int3537_0.bin 这几个对应 HI556 + INT3537。


4. 升级到 Linux 7.0(解决 int3472 GPIO type 0x12 unknown)

Debian 13 默认 6.12.90 内核的 intel_skl_int3472_discrete 不认识 GPIO type 0x12(IVSC handshake GPIO),导致 sensor 拿不到 power/reset 信号。Linux 7.0 已合入相关 patch:

sudo apt install -y -t stable-backports linux-image-amd64 linux-headers-amd64
sudo reboot   # 默认引导 7.0

坑 4:v4l2loopback DKMS 旧版(< 0.16)在 Linux 7.0 编译失败,要么先卸掉旧版让 dpkg 完成 kernel 安装,要么从 upstream master 装新版(本文后面会装)。

附带修 BE200 WiFi:Linux 7.0 启动后 WiFi 7 BE200 报固件版本不够:

sudo apt install -t stable-backports firmware-iwlwifi
sudo modprobe -r iwlwifi && sudo modprobe iwlwifi

5. Patch usbio:让它认 Dell 的 INTC10D1/D2/D3

mainline usbio-gpio 只匹配 INTC1007(标准 MTL),Dell Latitude 7450 用 INTC10D1(变种 ID)。从 intel/ipu6-drivers clone 源码 patch 后 DKMS 重建:

cd /opt/ipu6-src
sudo git clone --depth=1 https://github.com/intel/ipu6-drivers.git
sudo cp -r ipu6-drivers /usr/src/usbio-0.2   # DKMS 会从这里编

Patch GPIO/I2C/SPI 三个文件的 ACPI 表:

sudo sed -i '/{ "INTC1007" }/a\\t{ "INTC10D1" }, /* Dell Latitude */' \
  /usr/src/usbio-0.2/drivers/gpio/gpio-usbio.c
sudo sed -i '/{ "INTC1008" }/a\\t{ "INTC10D2" }, /* Dell Latitude */' \
  /usr/src/usbio-0.2/drivers/i2c/busses/i2c-usbio.c
# spi-usbio.c 同理加 INTC10D3

注册到 DKMS:

sudo dkms add -m usbio -v 0.2
sudo dkms build -m usbio -v 0.2 -k "$(uname -r)"
sudo dkms install -m usbio -v 0.2 -k "$(uname -r)" --force
sudo depmod -a
sudo modprobe -r i2c-usbio gpio-usbio usbio
sudo modprobe usbio && sudo modprobe gpio-usbio && sudo modprobe i2c-usbio

效果:之前 int3472: cannot find GPIO chip INTC10D1:00 死循环停了,sensor 的 i2c 设备 i2c-INT3537:00 出现在 /sys/bus/i2c/devices/。


6. Patch hi556:跳过 fwnode link-frequency 检查

sensor 终于能被 probe 了,但又卡新错:

hi556 i2c-INT3537:00: no link frequency 437000000 supported
hi556 i2c-INT3537:00: probe with driver hi556 failed with error -22

原因:hi556 driver 读 fwnode 里的 link-frequencies 属性来跟 driver 内部 link_freq_menu_items[](只有 437MHz)对比,但 ipu_bridge 没给 USB-IO i2c bus 上的 sensor 配 swnode(它只扫 PCH I2C bus)。fwnode 上的 link-frequencies 是 IVSC bridge 设的某个不同值。

Patch hi556 让它跳过这个交叉校验:

sudo apt install -y linux-source-7.0
cd /tmp && tar -xf /usr/src/linux-source-7.0.tar.xz --wildcards \
  "linux-source-7.0/drivers/media/i2c/hi556.c" --strip-components=4

在 hi556_check_hwcfg() 的 frequency 校验循环前插一行 goto check_hwcfg_skip;,并在 check_hwcfg_error: 标签前加 check_hwcfg_skip::

+    /* Dell quirk: ipu_bridge can't annotate USB-IO i2c sensors */
+    goto check_hwcfg_skip;
     for (i = 0; i < ARRAY_SIZE(link_freq_menu_items); i++) {
         ...
     }

+check_hwcfg_skip:
 check_hwcfg_error:
     v4l2_fwnode_endpoint_free(&bus_cfg);

写到 DKMS:

sudo mkdir -p /usr/src/hi556-dell-1.0
sudo cp hi556.c /usr/src/hi556-dell-1.0/
sudo tee /usr/src/hi556-dell-1.0/Makefile <<'EOF'
obj-m += hi556.o
KDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all:
    $(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
    $(MAKE) -C $(KDIR) M=$(PWD) clean
EOF
sudo tee /usr/src/hi556-dell-1.0/dkms.conf <<EOF
PACKAGE_NAME=hi556-dell
PACKAGE_VERSION=1.0
MAKE[0]="make KDIR=/lib/modules/\$kernelver/build"
CLEAN="make clean"
AUTOINSTALL="yes"
BUILT_MODULE_NAME[0]="hi556"
BUILT_MODULE_LOCATION[0]="."
DEST_MODULE_LOCATION[0]="/updates"
EOF
sudo dkms add -m hi556-dell -v 1.0
sudo dkms build hi556-dell/1.0 -k "$(uname -r)"
sudo dkms install hi556-dell/1.0 -k "$(uname -r)" --force
sudo depmod -a
sudo modprobe -r hi556 && sudo modprobe hi556

效果:hi556 i2c-INT3537:00: supply dovdd not found, using dummy regulator —— sensor 真正 probe 成功了。/dev/v4l-subdev* 出现新节点。


7. PSYS 权限

echo 'KERNEL=="ipu-psys*", MODE="0660", GROUP="video"' | \
  sudo tee /etc/udev/rules.d/99-intel-ipu6.rules
sudo udevadm control --reload
sudo udevadm trigger /dev/ipu-psys0

否则 HAL open(/dev/ipu-psys0) 报 EACCES,gst-launch 报 Failed to open PSYS。


8. 第一次出图!

export GST_PLUGIN_PATH=/usr/lib/gstreamer-1.0
gst-launch-1.0 icamerasrc num-buffers=10 ! \
  video/x-raw,format=NV12,width=1280,height=720 ! fakesink
# 收到 EOS = 10 帧出齐 = 摄像头工作 ✓

加 autovideosink 替换 fakesink 应该弹出窗口看到自己。

但是 —— Cheese / Edge / Chrome / Firefox / Teams 全都不能用。它们都不懂 GStreamer,只懂 V4L2 设备文件。


9. 桥接 icamerasrc → v4l2loopback

让浏览器和视频会议软件看到摄像头,要把 GStreamer 输出灌进一个虚拟 V4L2 capture 设备。

9.1 装新版 v4l2loopback

Debian 包的 v4l2loopback-dkms 0.15 在 Linux 7.0 编译失败,从 upstream master 装:

cd /opt/ipu6-src
sudo git clone --depth=1 https://github.com/v4l2loopback/v4l2loopback.git
sudo cp -a v4l2loopback /usr/src/v4l2loopback-master
sudo dkms add -m v4l2loopback -v master
sudo dkms build  v4l2loopback/master -k "$(uname -r)"
sudo dkms install v4l2loopback/master -k "$(uname -r)" --force

9.2 关键:选对 video 号

sudo tee /etc/modprobe.d/v4l2loopback.conf <<'EOF'
options v4l2loopback video_nr=49 card_label="IPU6 Camera (Bridged)" exclusive_caps=1 max_buffers=2
EOF

坑 5:video_nr 必须在 0-63 范围内!Chromium 内核的 V4L2 设备扫描默认上限就是 64,超过这个范围浏览器看不到。IPU6 占 0-47,所以选 49 是合适的(48 偶尔会被 IPU6 抢)。

坑 6:exclusive_caps=1 必须开!Chromium 排除同时声明 V4L2_CAP_VIDEO_CAPTURE + V4L2_CAP_VIDEO_OUTPUT 的设备。exclusive_caps=1 让 device 在被打开时锁成单向,bridge 服务先打开作 OUTPUT 后,subsequent open 就拿 CAPTURE-only 视角,浏览器才认。

9.3 udev 规则 + 让 Chromium 把它当摄像头

sudo tee /etc/udev/rules.d/99-v4l2loopback-public.rules <<'EOF'
SUBSYSTEM=="video4linux", KERNEL=="video49", MODE="0666", \
  ENV{ID_V4L_CAPABILITIES}=":capture:", ENV{ID_V4L_PRODUCT}="IPU6 Camera (Bridged)"
EOF
sudo udevadm control --reload
sudo modprobe v4l2loopback

坑 7:ID_V4L_CAPABILITIES=":capture:" 这个 udev 属性 Chromium 必须看到,否则即使设备有 V4L2_CAP_VIDEO_CAPTURE 标志也会跳过。这条 udev rule 是 v4l2loopback 上 Chromium 兼容的隐藏关键。

9.4 systemd 桥接服务

sudo tee /usr/local/bin/ipu6-camera-bridge.sh <<'EOF'
#!/usr/bin/env bash
set -e
export GST_PLUGIN_PATH=/usr/lib/gstreamer-1.0
for i in {1..30}; do [[ -c /dev/video49 ]] && break; sleep 1; done
exec gst-launch-1.0 -q icamerasrc ! \
  video/x-raw,format=NV12,width=1280,height=720,framerate=30/1 ! \
  videoconvert ! video/x-raw,format=YUY2 ! \
  v4l2sink device=/dev/video49
EOF
sudo chmod +x /usr/local/bin/ipu6-camera-bridge.sh

sudo tee /etc/systemd/system/ipu6-camera-bridge.service <<'EOF'
[Unit]
Description=IPU6 camera (icamerasrc) -> v4l2loopback bridge
After=systemd-modules-load.service
Wants=systemd-modules-load.service

[Service]
Type=simple
ExecStart=/usr/local/bin/ipu6-camera-bridge.sh
Restart=on-failure
RestartSec=3
EOF
sudo systemctl daemon-reload
# 注意:不要 enable,让用户按需启停

10. 手动开关脚本 cam on/off

桥接服务一开摄像头隐私灯就亮(producer 在持续抓帧),所以不让它自启动,给用户一个简单切换:

sudo tee /usr/local/bin/cam <<'EOF'
#!/usr/bin/env bash
case "${1:-status}" in
  on)     sudo systemctl start  ipu6-camera-bridge.service && echo "Camera ON  (privacy LED lit)" ;;
  off)    sudo systemctl stop   ipu6-camera-bridge.service && echo "Camera OFF (privacy LED off)" ;;
  status) systemctl is-active ipu6-camera-bridge.service ;;
  *)      echo "Usage: cam {on|off|status}"; exit 2 ;;
esac
EOF
sudo chmod +x /usr/local/bin/cam

sudo tee /etc/sudoers.d/ipu6-camera-bridge <<EOF
${USER} ALL=(root) NOPASSWD: /usr/bin/systemctl start ipu6-camera-bridge.service, \
                              /usr/bin/systemctl stop ipu6-camera-bridge.service
EOF
sudo chmod 440 /etc/sudoers.d/ipu6-camera-bridge

11. (可选)PipeWire 清理

PipeWire 默认把 IPU6 内部的 video0-47 全当 camera node 暴露,应用列表里会有 50+ 个"camera"。屏蔽掉内部节点,只留 Bridged:

sudo mkdir -p /etc/wireplumber/wireplumber.conf.d
sudo tee /etc/wireplumber/wireplumber.conf.d/51-hide-ipu6-isys.conf <<'EOF'
monitor.v4l2.rules = [
  {
    matches = [ { node.nick = "ipu6" } ]
    actions = { update-props = { node.disabled = true } }
  }
]
EOF
systemctl --user restart wireplumber

12. 关于 flatpak Edge

flatpak 版 Edge(com.microsoft.Edge)无法用 —— 即使给了 --device=all,沙箱内的 V4L2 enumeration 拿不到 video49。装 deb 版:

curl -fsSL https://packages.microsoft.com/keys/microsoft.asc | \
  sudo gpg --dearmor -o /usr/share/keyrings/microsoft.gpg
echo 'deb [arch=amd64 signed-by=/usr/share/keyrings/microsoft.gpg] \
  https://packages.microsoft.com/repos/edge stable main' | \
  sudo tee /etc/apt/sources.list.d/microsoft-edge.list
sudo apt update && sudo apt install -y microsoft-edge-stable
flatpak uninstall -y com.microsoft.Edge

13. 验证

cam on
v4l2-ctl --device=/dev/video49 --all | head -25
# 期望看到:
#   Driver name : v4l2 loopback
#   Card type   : IPU6 Camera (Bridged)
#   Video input : 0 (loopback: ok)         ← 关键:ok 不是 no signal
#   Pixel Format: 'YUYV' 1280x720

测试网页:

应用验证清单:

应用状态
Firefox(含 Teams Web 之外的网站)✅
Microsoft Edge (deb)✅
Chromium / Chrome (deb)✅
Microsoft Teams(deb Edge 里跑 web 版)✅
飞书 Linux 客户端✅
OBS Studio(V4L2 source 选 video49 / 或直接 GStreamer source icamerasrc)✅
Cheese / Kamoso / GNOME Snapshot❌(应用本身 bug)
flatpak 版 Edge / Chrome❌(沙箱挡)
Firefox 打开 Teams Web❌(微软限制 Firefox)

整体架构图

  Hynix HI556 sensor (10-bit raw Bayer)
       │
       │  i2c (via INT3537 ACPI node)
       │
  USB-IO Bridge  ← patched usbio DKMS (加 INTC10D1/D2/D3)
       │
       │  power/clock (via int3472, 配合 IVSC handshake GPIO)
       │
  IPU6 ISP (Meteor Lake)
       │
       │  process: demosaic → AWB → AE → AF → NV12
       │
  intel-ipu6-camera-hal (libcamhal.so + libipu6epmtl.so)
       │
       │  GStreamer element
       │
  icamerasrc (/usr/lib/gstreamer-1.0/libgsticamerasrc.so)
       │
       │  push frames (systemd service)
       │
  v4l2loopback /dev/video49  ← exclusive_caps=1, ID_V4L_CAPABILITIES=:capture:
       │
       │  open() by app
       ▼
  Edge / Firefox / Teams / 飞书 / Zoom / OBS

一句话总结

任何一个环节配置不对就全盘失效。 Linux + IPU6 + 浏览器 = 跨内核 / 固件 / ACPI / 用户态 HAL / GStreamer / v4l2loopback / udev / Chromium 过滤规则 / sandbox 11 层全对齐才能用。希望这篇文章能帮后来的人省几小时。

DKMS 包内核升级会自动重建,但万一某次升级出问题,本文每条命令都可以重新跑。


引用 / 资源

debian 系统降级[测试版 降级至 稳定版]

edit /etc/apt/sources.list

deb http://mirrors.ustc.edu.cn/debian stable main contrib non-free
deb-src http://mirrors.ustc.edu.cn/debian stable main contrib non-free
deb http://mirrors.ustc.edu.cn/debian stable-updates main contrib non-free
deb-src http://mirrors.ustc.edu.cn/debian stable-updates main contrib non-free

deb http://mirrors.ustc.edu.cn/debian stable-backports main contrib non-free
deb-src http://mirrors.ustc.edu.cn/debian stable-backports main contrib non-free

deb http://mirrors.ustc.edu.cn/debian-security/ stable/updates main non-free contrib
deb-src http://mirrors.ustc.edu.cn/debian-security/ stable/updates main non-free contrib

Modify or create the file /etc/apt/preferences and put following text in it:

Package: *
Pin: release a=stable
Pin-Priority: 1001

run command

apt-get update
apt-get upgrade
apt-get dist-upgrade

RSA 密钥格式详解

密钥保存方式

PEM格式

PEM格式包含几种报文头
"-----BEGIN PUBLIC KEY-----": PKCS#8 格式公钥
"-----BEGIN PRIVATE KEY-----": PKCS#8 格式私钥

"-----BEGIN RSA PUBLIC KEY-----": PKCS#1 格式公钥
"-----BEGIN RSA PRIVATE KEY-----": PKCS#1 格式私钥

公钥

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDX2k9fV+TXr0sIw/oGI9v2g+Nm
Drf16cdfK45oPEyEGH0sqcYvvTTjD2iovHltOMCidgV2TH+S0bIb6JEoPaW7/+ya
tX3+MvHpCnOylaDH5aKNKoy/JyRn/cy9TXAk0QLAlKTCnfP1A3s5WqRDO2f6B70r
imffp9gfs/SVVhjy0wIDAQAB
-----END PUBLIC KEY-----

私钥

-----BEGIN PRIVATE KEY-----
MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBANfaT19X5NevSwjD
+gYj2/aD42YOt/Xpx18rjmg8TIQYfSypxi+9NOMPaKi8eW04wKJ2BXZMf5LRshvo
kSg9pbv/7Jq1ff4y8ekKc7KVoMfloo0qjL8nJGf9zL1NcCTRAsCUpMKd8/UDezla
pEM7Z/oHvSuKZ9+n2B+z9JVWGPLTAgMBAAECgYEAjn9nwNikkaL+lRXTvDP2JaLh
/2EeHvErlm+JvtR36wjDsjWOSbvN60wj2qk6PFmoCliBuJw96C4ZOAVrtrYj72cy
WvCg302y8Ugc8JjSuQMaDFck5jAD1rWt4IyZnHgogjryOAZ8KTl8kfAqCWIPS2BS
xIWZojhphn/vWkCYMWECQQDzLOgEF7mGUtx14B9ezJ2DS+iKV6k5lSWTGO4AqZ1g
T+lOLiNo5PuDMxSTMvuUQVULda4Su0EI4zqmlcr7C3axAkEA4zyF0YAdPWjNTy+s
ezQ5NpZuj5K9A2xAAu0Y1vp8bJGSt8oZdGewtL/QHSylJbG+xKiMRo5g9xwkkx0W
M0yqwwJBALVF5ncWkHA3WKxuNDRg55I2hdSK4FVSfz4WOWU5C13+c/aZoj/RYkQ9
UbshKDUuNo1iXi8Mc8CCUvhXdYaK1yECQHCxtVP/C4FHFnstE4dOkQlHdbFyfpbR
+rT4zRbgxxA46eCINDOMsRATCK1PVN/q1MdHJ7peJiynImRrSnVKkm0CQQCpmnAg
UnByBn4BJBgA26WRx/ag2S4gEU9TMnW+vMPFfscMvzMuOy34phlQqbHyniHi9Y5r
i7mELpNVp45VGi0l
-----END PRIVATE KEY-----

ASN格式

内容是PEM格式密钥中间的Base64段,密钥格式如下:

公钥

MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDoUK4y6LX1kiHu0ubO1C1wRBrcgdSXBwI4CRuKK1fpTsS2dHpB5V+wQ63Rts3Ohr0E+pqIlaFu77Kp/UTczTH5dzSi4vdsexCBSnqC9RZLftadskTlf7OlHrF9Emva3s7Yla73EY56Jb0E/CS/PjKuNDNZ2CoZc2c3YBHDtObvhQIDAQAB

私钥

MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAOhQrjLotfWSIe7S5s7ULXBEGtyB1JcHAjgJG4orV+lOxLZ0ekHlX7BDrdG2zc6GvQT6moiVoW7vsqn9RNzNMfl3NKLi92x7EIFKeoL1Fkt+1p2yROV/s6UesX0Sa9reztiVrvcRjnolvQT8JL8+Mq40M1nYKhlzZzdgEcO05u+FAgMBAAECgYByqsAQ6MRHfeW51+eM1zXGYBdSF9My6Iaz2er5/ALcacC2vi9KL0lX21AEX1KeSesqdfeoyxJvi2iIdzZyNeYf52JUvvhnwedDu7YKi6xFgjvBbCPmifbau/r3JELQDHqRbnpYIe1NLrz9D0QBST5skGrYmeQe9NvVKEMMFuwPAQJBAPnTQI4AArADapYQjQnIE2Z94f1sAFkmvuI0kHikXFJKZ+CSWLw+vYrRkV1ct+Am2nz244e1AIcVG/iteYMs13UCQQDuDqKNFT43crjquJt3EzQWLxvQaK+bIKGVjcWje2xSH5oCiyPCk2RhWjd46aSPViPwyn5RPjsy0+EwLrm7xsXRAkAVbVYLF9sjJ5fbuR2vqhZn4wIgD0RUYStcEXAWuNomQLV6IHM16hetsV3LaSloM0zoDPDk8dRSwa+9e3uBkbYFAkAFOw0XTIAxd7PYdHX2B9X9JsvVqHczUWQ7hQHytaOLqmYX6DbA77wk53aQkZGsFJh1kf10i4mBdGZeSKiMF7IBAkAhniFbHF4G0RKxCJ3paII0m7qn3eI+pIPEGFX3sZjMYaYtWV9WmbvxytSdv88pa1Mh/ZxZjZTjsp0cq+XffD3r

XML格式

C# 默认的格式,密钥格式如下:

公钥

<RSAKeyValue><Modulus>riLSQFVDC229P5F+Mkicbkpg5OC8+SeL6hvkJXIGYiN/e4YnprCxuIp5sH9AwWup4WJmObPKd1jOVGm07UwgVU7CDtTaVe1Uuk78yJBwgRuSteQjHYMmH6nG5YHvvONuvkmLnyIKGygJBL+4+Qmd3GaCHRtIrdfShlH3UbPINlM=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>

私钥

<RSAKeyValue><Modulus>riLSQFVDC229P5F+Mkicbkpg5OC8+SeL6hvkJXIGYiN/e4YnprCxuIp5sH9AwWup4WJmObPKd1jOVGm07UwgVU7CDtTaVe1Uuk78yJBwgRuSteQjHYMmH6nG5YHvvONuvkmLnyIKGygJBL+4+Qmd3GaCHRtIrdfShlH3UbPINlM=</Modulus><Exponent>AQAB</Exponent><P>6yCboYtKzIezMOFzGzzW8dp7SBT8f7jTRzH1ZIKQYKF0Mq/39k80SeUvY578O031+bg6i3cbNvvAhL8XjqTtmQ==</P><Q>vZgnL5LHnNE5uUW5NBwYvZbIz6hWNzc6kyDGimI8WBBFJOI06IdYGL2VMeGVs4lt5a1tM7T3c6gzBKgDQpL+yw==</Q><DP>p5tV9YDyr/unq5d6Uxc6bar9qHN1TqJ00VJ2h9BelNNinmM70fPB5U8fSddiG/BGAF3oNdSQrNAm+zmw1DkTOQ==</DP><DQ>fxS1b1XbJmm3X1A0y5DppGqlP0t+PpRuVp/pdGhUOlLthcN540KU8kBg+IZUaXr8hq6wO7BZDNT5HW3ggYc18Q==</DQ><InverseQ>q29etXnlszOH0FlQWDL9yLfJ+EruH4VURY1mZGz/+/qvPewUwyEf+EqJkZHVXEijnSa1CiFELK2YE9PhkUp2Xw==</InverseQ><D>bZUoLqf5KwYCJDDQ85/SIW3ZD++FvF1wpQCsUAwzjCq+nONNrI5hKLqr3bAW9iFkpJshrYpBDV3rah+jZfmUFk/UZeur2+kA2r5r1or34+HiIhT4sehU1lxww4DvTzf1/1ivG4LCvUPoFtT67Zdh8pNEC27N6bFDL8fbSU7GcmE=</D></RSAKeyValue>

DER 格式

直接对二进制密钥进行binToHex后得到的密钥格式,密钥格式如下:

公钥

30818902818100C19CFA5EA25F99C482499E3A557C7D0C3ABB375B19900CF4956E39F5B1EACA46A37CEE30DDBEA72979B6DABA11D4B9BD51CB1D79ED667607E65CF53491EE6BE35155072D5EFB96BA0E0FC0B9C1DFEDFA30886F645218CC680E55A7D5568AD59283E9BB3DC82970F6B3F6DD83FB308E2C610F362C71977D428614ED5FB59EFDB10203010001

私钥

3082025D020100028181009951BFB322876658587C207F2AFC2F2638DFD4EEEE925669C4A9487A3774891AEBE638940318B1AE270784FCFBE768C8C989E33B3953D820326DFAC7862AA133F96EE216C1B3F5651D45194CA02E9926E8FF133B2C03BB22BFE8C60B13D4757F263D4A792B188A8183FAB53B193C8AF8AB8EAB7020547C20D5BC90E1B369DBA902030100010281800FD9829ECB28022D89E0331FD25AC5A906E224CA1A81A84B40D85B34BF3CDDDB999D7025E4F80D8E3A5CADA3D58AC3AB56225A0A4A4FDF9CDC79C01E16419BEE71997546C68E6408E5D9C044858DCB6393F285D3EBAAD0C75298F61B33B752EB8E1ABA4D66E5380FF52DE07929A96367673CDAE5945A0C13F3503FABEDB1758D024100C52F9745C13B77968D52F29ACDEE00F2DF07AF8025048348B054B7EFF460097CAB824212447F674B55CF74E489DD399E702D3D655C74484248E05CA2E9DCCEE7024100C70CA9EA361ED73C42627254F33A3FA81AD0AADD64D45A1E536E64C7E31737B7ED3FCC20E03A082673C6E7A7270640F6132AA295FF406D6133090E7D89397EEF024100883505936395065872AAB77683854216824536CF97C2744543B8618E5909F5C3AE5D3DF28C6A4D19D6DE84EA50E905A211EECE18343306AEF2D43869388E1445024100B061FE6776D1D974A276CE4D8CC2FF099DC96EBF84CBCF97B3E2CD177B9A655B6CB6EDD1EC20407CA2778D6B475F794D152AE0ABFE663F06B4CCBFB46A5732AD02404981E8728E85719A319C9A8C4C7D3B162BFA728AD5FD054C0A45A9A625385167F0822D2398680FD75BF29A3C20A4D72D2115ABD06F27B3819214AAC77284518A

密钥内容格式

以下均以DER格式为例

公钥

一般情况,我们会遇到两种格式公钥PKCS#1 和PKCS#8,密钥结构如下:

后续(到结尾)内容长度为0x9F字节,相当于整个文件长度-当前这3字节。
格式:type[+长度数据占用位数(可选)]+后续长度数值,
    此处type=0x30,
    长度数据占用1位(参考前面长度表述方法),
    后续长度数值=0x9F个字节

直观JSON化ASN.1(后面新学的ASN.1结构):
30_SEQUENCE{
    03_BIT_STRING: "二进制内容(看是什么,也许是纯二进制,或者是一个可以解析成ASN.1格式的内容)"
    , 05_NULL: "NULL,后面内容长度为0"
    , 30_SEQUENCE:{
        02_INTEGER: "整数"
        , 02_INTEGER: "整数"
        , 02_INTEGER: "整数"
    }
}
*/
30 81 9F //容器[30 SEQUENCE] [81 长度数据占1位] [9F 容器内有9F字节数据]

    /*
    固定内容,长度为0x0D个字节,为RSA OID(1.2.840.113549.1.1.1)

    RSAES-PKCS1-v1_5 encryption scheme: http://www.oid-info.com/get/1.2.840.113549.1.1.1
    */
    30 0D //容器[30 SEQUENCE] [0D 容器内有0D字节数据]
        06 09 2A864886F70D010101 //06 OID 1.2.840.113549.1.1.1
        05 00 //NULL

    /*后续内容长度,后面内容长度为0x8D字节,和开头格式一致*/
    03 81 8D //03 BIT STRING,后面放的是二进制公钥数据,此内容其实还是一个结构
        00 //BIT STRING内容前面需要加00

        /*后续内容长度,后面内容长度为0x89字节,和开头格式一致*/
        30 81 89 //容器[30 SEQUENCE] [81 长度数据占1位] [89 容器内有0x89字节数据]

            /*
            RSA Modulus内容
            格式:type[+长度数据占用位数(可选)]+内容长度数值+内容,
                此处type=0x02,所有RSA相关参数都是用02,
                长度数据占用位数为1字节,
                内容长度数值=0x81个字节,
                内容为0x00-0x27这一段(参考前面什么情况下要加0x00)。
            */
            02 81 81 //02 INTEGER整数[02 INTEGER] [81 长度数据占1位] [81 Modulus内容长x81字节]
                               0098C3DF8CDFE444CC3B58AB006BB3F6ACFCECBC1911393A69EA395D047E41220888E27336D51059D9DEA4632DB0C04DF981C4D43A73A1606BC9D7DBC825107FDA2FF446D8A76923C28C52A280B3337276C1D27A1F4C48A71DE73812E0DB84D2EF9E47B081F243968A988B0D0998DFC929337EA945674D425A486930E8E4884927

            /*RSA Exponent内容,和Modulus一样,但此处长度数据占用位数不存在*/
            02 03 //02 INTEGER整数[02 INTEGER] [03 Exponent内容长x03字节]
                010001

私钥

/*后续内容长度,后面内容长度为0x025C个字节,和公钥开头格式一致,参考公钥部分*/
30 82 025C

    /*固定版本号*/
    02 01
        00

    /*#####从这里开始后面就是内容了 注:KCS#8仅仅是在此处插入部分内容#####*/

    /*RSA Modulus内容,和公钥开头格式一致,参考公钥部分*/
    02 81 81 
        0098C3DF8CDFE444CC3B58AB006BB3F6ACFCECBC1911393A69EA395D047E41220888E27336D51059D9DEA4632DB0C04DF981C4D43A73A1606BC9D7DBC825107FDA2FF446D8A76923C28C52A280B3337276C1D27A1F4C48A71DE73812E0DB84D2EF9E47B081F243968A988B0D0998DFC929337EA945674D425A486930E8E4884927

    /*RSA Exponent*/
    02 03
        010001

    /*RSA D*/
    02 81 80
        706352591AF29E26BED689DFE25CE0F2FD94D10184295D2F44D174FC744248DE8C8E45032717437345181D9B24B925E49533108BFC3BD26B1A710351A8EB0D937D8EEAF54FC6BE0D7D355A215E7D26FF59E525C6891991657791C3492C29874EC1A0C926EF73113347668305266F2CABFB4624F4023CD7ACA19459B2C2FB9A39

    /*RSA P*/
    02 41
        00CE23A8CAB7AD1BBEEE955EFB50A325146F2323F5E08E05AB52E3D8D1BEFDF6E9331CF79D5EF5371B9C3D1CC49AD5D4DEB2222FBEF9E8F07DA81B7987FEF8DEB5

    /*RSA Q*/
    02 41
        00BDB73C2939416C8F533309D5910A6CB7E724826DE0A510E101F43F2EDEEBF20D8A007B09BFEC1B0090A0BBC3E0A8CF6642357167EEFCF9A2C443E879AEF315EB

    /*RSA DP*/
    02 40
        63573DFDCB7C8A157E66CFAA2F57200473F6AC5ACEC7C2A5A8C192F8A9A13C3F6FD972DF0D270152B5FDA18281D7B0C94D713A2F3FC2693B352B606B108E20CD

    /*RSA DQ*/
    02 41
        009210B3D7216807C749CD6FF2E85AD85DB72EDAE4F222E49DF8BD2EB04D9DE79D18F549C5B5E878D9B480AC50217697482A0DAFA4CFD221F97996B73488C84BC5

    /*RSA InverseQ*/
    02 40
        06F0F9DD96248A27FAFB94B0A93676D653A99C7C7B9DCDADE65414C6889284B924F26A23AFFA86AF3FD804453B73FDFEA9310CC909BFC9928D5F757198B1075D

参照如上格式,密钥间的相互转换也就非常简单了。

密钥格式转换

DER -> ASN

ASN = encode_base64(decode_hex(DER))

ASN -> PEM

PEM = "-----BEGIN PUBLIC KEY-----" + ASN + "-----END PUBLIC KEY-----"

另付,各种格式密钥再C# 中使用。

RSA_CSharp

南京威玛斯特智能科技有限公司[物联网,我们更专注安全]-分享

jenkins 插件下载失败解决

欺骗jenkins 我要去清华真实下载插件

绑定 mirrors.jenkins-ci.org host 到本机

$ grep jenkins /etc/hosts
### jenkins ###
127.0.0.1 mirrors.jenkins-ci.org

nginx反向代理到清华

# root @ web-devops-01 in /usr/local/nginx/conf/vhost [23:32:55]
$ cat mirrors.jenkins-ci.org.conf
server
    {
        listen 80;
        server_name mirrors.jenkins-ci.org;

        location / {
            proxy_redirect off;
            proxy_pass https://mirrors.tuna.tsinghua.edu.cn/jenkins/;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Accept-Encoding "";
            #proxy_set_header User-Agent "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.49 Safari/537.36";
            proxy_set_header Accept-Language "zh-CN";
        }
        index index.html index.htm index.php;

        #error_page   404   /404.html;

        location ~ /\.
        {
            deny all;
        }

        access_log  /data/weblog/xx.access.log;
        error_log   /data/weblog/xx.error.log;
    }